├── .gitignore
├── Examples
├── TODO.txt
├── code examples
│ ├── MIDI control.scd
│ ├── Pattern support.scd
│ ├── VBAP.scd
│ ├── creating a FreeUdef.scd
│ ├── draw crossfades.scd
│ ├── draw wavefields.scd
│ ├── generatig session.scd
│ ├── generating lots of events score.scd
│ ├── generating scores.scd
│ ├── import v1 WFSPathArray xml.scd
│ ├── mass editing.scd
│ ├── path editor control.scd
│ ├── point constellations.scd
│ ├── score playback control 1.scd
│ ├── score playback control 2.scd
│ ├── speaker test generator.scd
│ ├── touchosc example.scd
│ ├── touchosc wfs.touchosc
│ └── udefs and io.scd
├── developer tests
│ ├── LoadBalancer tests.scd
│ ├── Spec guis test.scd
│ ├── Test FilePlayers 0.1.scd
│ ├── Test sample sched.scd
│ ├── VBAP.scd
│ ├── load panner synthdefs.scd
│ ├── sample sched simple test case - supernova.scd
│ ├── sample sched simple test case.scd
│ ├── test UScoreEditor rendering.scd
│ └── test polygon inside detection.scd
└── example scores
│ ├── constellations.uscore
│ ├── live input.uscore
│ ├── local udef.uscore
│ ├── lots of events.uscore
│ ├── rain
│ ├── rain.uscore
│ ├── rainHF.scd
│ ├── rainLF.scd
│ └── rain_and_drops.uscore
│ ├── simple automation.uscore
│ ├── speaker tests
│ ├── bea7 speaker test.uscore
│ ├── game of life speaker test.uscore
│ └── sampl speaker test.uscore
│ ├── trajectory generation.uscore
│ ├── user udef.uscore
│ └── user udef
│ └── sinGrain.scd
├── HelpSource
├── Guides
│ ├── UChain-GUI.png
│ ├── UScoreGUi.png
│ ├── WFSCollider-Code.schelp
│ ├── WFSCollider-Overview.schelp
│ ├── WFSCollider-Panners.schelp
│ ├── WFSCollider-Visual-Guide.schelp
│ ├── WFSPathGUI.png
│ ├── wfsDynamicIndex.png
│ ├── wfsDynamicPlane.png
│ ├── wfsDynamicPoint.png
│ ├── wfsStaticIndex.png
│ ├── wfsStaticPlane.png
│ └── wfsStaticPoint.png
├── Reference
│ └── WFS-theory.schelp
└── Tutorials
│ ├── WFS-Tutorial-1.png
│ ├── WFS-Tutorial-2.png
│ └── WFSCollider-tutorial.schelp
├── README.markdown
├── Session Templates
├── 8 live sources with path player.usession
└── 8 live sources without path player.usession
├── V1-Compatibility
└── WFS Classes
│ ├── Engine
│ ├── WFSServers.sc
│ ├── WFSSynth.sc
│ ├── WFSSynthDef.sc
│ └── wfsSynthPlus.sc
│ ├── Score Objects
│ └── WFSEvent.sc
│ ├── Spatial Objects
│ ├── WFSPath.sc
│ ├── WFSPathArray.sc
│ ├── WFSPlane.sc
│ ├── WFSPoint.sc
│ ├── WFSPointArray.sc
│ └── asWFSPoint.sc
│ ├── WFSTools.sc
│ └── wfsXMLSupport.sc
├── WFS
├── ArrayTransformer
│ ├── ArrayEditView.sc
│ ├── ArrayGeneratorDefs
│ │ ├── brown.scd
│ │ ├── line.scd
│ │ ├── linrand.scd
│ │ ├── pulse.scd
│ │ ├── random.scd
│ │ ├── sine.scd
│ │ ├── spline.scd
│ │ └── tri.scd
│ ├── ArrayTransformer.sc
│ ├── ArrayTransformerDefs
│ │ ├── clip.scd
│ │ ├── curve.scd
│ │ ├── offset.scd
│ │ ├── rotate.scd
│ │ ├── round.scd
│ │ ├── scale.scd
│ │ ├── smooth.scd
│ │ ├── sort.scd
│ │ └── tilt.scd
│ ├── ArrayTransformerView.sc
│ └── extArrayGeneratorDef-prMakeArgViews.sc
├── GUI
│ ├── AudioDeviceSpec.sc
│ ├── UBasicEditView.sc
│ ├── WFSEditViews.sc
│ ├── WFSOptions
│ │ ├── WFSMasterOptionsGUI.sc
│ │ └── WFSOptionsGUI.sc
│ ├── WFSPath
│ │ ├── WFPathBufferView.sc
│ │ ├── WFSPathGUI.sc
│ │ ├── WFSPathTransformerView.sc
│ │ ├── WFSPathView.sc
│ │ ├── extSimpleTransformerDef-makeViews.sc
│ │ ├── extWFSPath-draw.sc
│ │ └── extWFSPathGeneratorDef-prMakeArgViews.sc
│ ├── WFSPositionTrackerGUI.sc
│ ├── WFSRectView.sc
│ └── WFSSpeakerConf
│ │ ├── WFSArrayConfGUI.sc
│ │ ├── WFSSpeakerConfEditor.sc
│ │ ├── WFSSpeakerConfGUI.sc
│ │ └── WFSSpeakerConfView.sc
├── UMapDefs
│ ├── circle_trajectory.scd
│ ├── clip_point.scd
│ ├── crossfade_point.scd
│ ├── delay_point.scd
│ ├── envir_point_get.scd
│ ├── follow_point.scd
│ ├── index_trajectory.scd
│ ├── lag_point.scd
│ ├── lag_polar.scd
│ ├── line_trajectory.scd
│ ├── map_control_point.scd
│ ├── map_point.scd
│ ├── map_polar.scd
│ ├── mirror_point.scd
│ ├── motion_trajectory.scd
│ ├── p_circle_point.scd
│ ├── p_envir_point_get.scd
│ ├── p_line_point.scd
│ ├── p_map_point.scd
│ ├── p_map_polar.scd
│ ├── p_randomwalk_point.scd
│ ├── p_sequencer_point.scd
│ ├── point_angle.scd
│ ├── point_axis.scd
│ ├── point_direction.scd
│ ├── point_distance.scd
│ ├── point_in_rect.scd
│ ├── point_poll.scd
│ ├── point_speed.scd
│ ├── random_point.scd
│ ├── random_trajectory.scd
│ ├── rotate_point.scd
│ ├── sample_and_hold_point.scd
│ ├── scale_point.scd
│ ├── select_8_point.scd
│ ├── shared_point_in.scd
│ ├── shared_point_out.scd
│ ├── slew_point.scd
│ └── trajectory.scd
├── UNodeIDAllocator.sc
├── UPanCenter
│ └── USpeakerConf.sc
├── UScore-openWFS.sc
├── USharedPointIO.sc
├── UnitDefs
│ ├── envir_point_set.scd
│ ├── furseDistanceFilter.scd
│ ├── shared_point.scd
│ ├── simpleReverb.scd
│ ├── wfsCirclePath.scd
│ ├── wfsDynamicDirectional.scd
│ ├── wfsDynamicIndex.scd
│ ├── wfsDynamicPlane.scd
│ ├── wfsDynamicPoint.scd
│ ├── wfsIndex.scd
│ ├── wfsMasterIn.scd
│ ├── wfsMasterOut.scd
│ ├── wfsPathPlayer.scd
│ ├── wfsPathSequencer.scd
│ ├── wfsPoint.scd
│ ├── wfsRandomPath.scd
│ ├── wfsServerIn.scd
│ ├── wfsSource.scd
│ ├── wfsStaticIndex.scd
│ ├── wfsStaticPlane.scd
│ └── wfsStaticPoint.scd
├── UnitRacks
│ ├── wfsSimpleReverb.scd
│ └── wfsTrajectory.scd
├── WFSArrayPan.sc
├── WFSArrayPanDir.sc
├── WFSArrayPanDirSpecs.sc
├── WFSArrayPanDirSynthDefs.sc
├── WFSArrayPanSynthDefs.sc
├── WFSFocusDetector.sc
├── WFSFocusDetectorSynthDefs.sc
├── WFSLib.sc
├── WFSOptions.sc
├── WFSPath
│ ├── SimpleTransformer.sc
│ ├── WFSMultiPath.sc
│ ├── WFSPath2.sc
│ ├── WFSPathBox.sc
│ ├── WFSPathBuffer.sc
│ ├── WFSPathEditor.sc
│ ├── WFSPathGeneratorDefs
│ │ ├── align.scd
│ │ ├── brown.scd
│ │ ├── circle.scd
│ │ ├── line.scd
│ │ ├── lineTime.scd
│ │ ├── lissajous.scd
│ │ ├── orbit.scd
│ │ ├── polygon.scd
│ │ ├── randTime.scd
│ │ ├── random.scd
│ │ ├── round.scd
│ │ ├── sine.scd
│ │ ├── spiral.scd
│ │ └── spline.scd
│ ├── WFSPathPlayer.sc
│ ├── WFSPathTransformer.sc
│ ├── WFSPathTransformerDefs
│ │ ├── circleSize.scd
│ │ ├── clip.scd
│ │ ├── duration.scd
│ │ ├── equal.scd
│ │ ├── move.scd
│ │ ├── name.scd
│ │ ├── reverse.scd
│ │ ├── rotate.scd
│ │ ├── scale.scd
│ │ ├── simpleSize.scd
│ │ ├── size.scd
│ │ ├── smooth.scd
│ │ ├── sort.scd
│ │ └── type.scd
│ ├── WFSPathURL.sc
│ ├── WFSPointGroup.sc
│ ├── WFSPointGroupGUI.sc
│ └── WFSSplinePath.sc
├── WFSPositionTracker.sc
├── WFSPreviewSynthDefs.sc
├── WFSSpeakerConf.sc
├── WFSV2.sc
├── WFS_Specs.sc
├── ext_v1_import.sc
├── resources
│ └── binauralIRs
│ │ ├── README.txt
│ │ ├── irsOrd1.wav
│ │ ├── irsOrd2.wav
│ │ ├── irsOrd3.wav
│ │ ├── irsOrd4.wav
│ │ ├── irsOrd5.wav
│ │ ├── irsOrd6.wav
│ │ └── irsOrd7.wav
└── wfs_synthdefs.zip
├── WFSCollider-Class-Library.quark
└── gpl.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/Examples/TODO.txt:
--------------------------------------------------------------------------------
1 | WFS TODO / ideas (no particular order)
2 |
3 | - re-invent preview system;
4 | - generic panners with settings for different spatialization methods
5 | - new interface for point sources and plane waves
6 | - move trajectory etc to Unit Lib
7 |
8 | - subwoofers
9 | - directional point sources
10 | - Folder events / sub-scores:
11 | - implement cutting sub-scores
12 | - inner score looping.
13 | - MultiUdef: being able to select defs by index instead of defName
14 | - HiddenUdef is then obsolete; it can simply use Udefs with addToAll:false
15 | - WFSServers: better gui
16 | - button for loading al udefs
17 | - working buttons for server management (now that the ssh problem is fixed)
18 | - panic button (stop all - not kill)
19 | - loaded buffers / synths indicator
20 | - WFSPath
21 | - implement free spline wfspaths
22 | - create preset system for WFSPaths ("path banks")
23 | - rename to WFSPath; subclass of Trajectory
24 | - more generators:
25 | - import SVG
26 | - import MIDI
27 | - more basic shapes
28 | - export SVG
29 | - export MIDI?
30 | - WFSMultiPath: timeline display and better support
31 | - save/read from WFSPathGUI
32 | - unified save/read system (Buffer:write vs. SoundFile)
33 | - add trigger option to wfsPathPlayer Udef
34 | - gui for RichBufferSpec
35 | - UMixer for session
36 | - MassEdit:
37 | - more options for wfspath massedit
38 | - core:
39 | - allow change of units in chain during playback
40 | - clear all option (in case buffers or synths are kept by mistake)
41 | - handle buffer-not-found correctly (i.e. give user option to cancel playback)
42 | - may require a do-on-failed action/method
43 | - fix release problem for non-releaseself events
44 | - more documentation
45 |
46 | - future ideas
47 | - implement score position jumping during playback, without stopping the score (similar to pause)
48 | - pattern-like generator interface for events
49 | - midi import
50 | - option for midi import of timeline/meter settings
51 | - option to show waveforms in path editor
52 | - possibly as width of the trajectory line
53 | - clipboard (copy/paste) for WFSPathGUI
54 | - Right-click menu
55 |
--------------------------------------------------------------------------------
/Examples/code examples/MIDI control.scd:
--------------------------------------------------------------------------------
1 | /*
2 | this example for WFSCollider demonstrates how to program midi control for your score. It creates a very simple score with a sine wave in the center of the room, with infinite duration. The frequency of the sine wave is controlled via the modulation wheel (cc 1), mapped to the whole frequency range (20-20000Hz).
3 |
4 | Items with multiple lines in between brackets ( () ) are meant to be executed together. Double click one of the brackets to select the whole block. Other items can be executed as single lines.
5 |
6 | Note that this is an alternative to the 'midi' UMapDefs (midi_bend, midi_cc etc..).
7 | */
8 |
9 | // define a simple score
10 | x = UScore( UChain( [ \sine, [ \lag, 0.1 ] ], [ \wfsSource, [ \point, \lag_point ] ] ) );
11 |
12 | // open the score editor to see it:
13 | x.gui;
14 |
15 | // play the score (or hit play button in editor)
16 | x.prepareAndStart;
17 |
18 | // couple controller 1 (modulation wheel) on any channel to the frequency of the sine wave
19 | MIDIIn.connectAll; // needs to be runned once
20 |
21 | (
22 | m = MIDIFunc.cc({ |val, num, chan, src|
23 | x[0][0].freq = val.linexp(0,127,20,20000); // points to first unit of first chain in the score
24 | }, 1 ); // <- the '1' here filters for controller number 1
25 | )
26 |
27 | // if no midi controller is connected, use the lines below to
28 | MIDIIn.doControlAction(1, 1, 1, 50); // spoof a cc (value 50)
29 | MIDIIn.doControlAction(1, 1, 1, 70); // spoof a cc (value 70)
30 |
31 | // remove the action (cmd-. also removes it)
32 | m.free;
33 |
34 | // stop the score
35 | x.stop;
36 |
37 |
38 | // other ways to do the same:
39 |
40 | (
41 | // using .set on the UChain will find all units with the 'freq' parameter name, and set those
42 | m = MIDIFunc.cc({ |val, num, chan, src|
43 | x[0].set( \freq, val.linexp(0,127,20,20000) );
44 | }, 1 );
45 | )
46 |
47 | (
48 | // via mapSet the associated ControlSpec of \freq can be used to scale the value from the (0-1) range
49 | m = MIDIFunc.cc({ |val, num, chan, src|
50 | x[0][0].mapSet( \freq, val.linlin(0,127,0,1) );
51 | }, 1 );
52 | )
53 |
54 | (
55 | // using the built-in midi_cc UMapDef the score would be created like this:
56 | y = UScore(
57 | UChain(
58 | [ 'sine', [ 'freq',
59 | [ 'midi_cc', [ 'active', true, 'cc', 1, 'toRange', [ 20, 20000 ] ] ] ] ],
60 | [ 'wfsSource', [ 'point', 'lag_point' ] ]
61 | )
62 | );
63 | y.gui;
64 | )
65 |
--------------------------------------------------------------------------------
/Examples/code examples/Pattern support.scd:
--------------------------------------------------------------------------------
1 | // generate a proto event
2 | (
3 | x = UChain( [ 'formant', [ \bw, 1 ] ], [ 'wfsSource', [ \latencyComp, 1 ] ]);
4 | x.gui;
5 | )
6 |
7 | ( // drone
8 | z.stop;
9 | y = Pbind(
10 | \dur, Pwrand( [1,2], [0.9,0.1], inf ) / 10,
11 | \legato, Pbrown( 0.5, 1.5, 0.25, inf ),
12 | \formant, Pbrown( 0.0,1, 0.3).linexp(0,1,110,1000),
13 | \freq, Pwrand( [ 55, 110, 220 ], [ 0.1, 0.8, 0.1 ], inf ),
14 | \point, Pwhite( (-20.0 @ -20.0), (20.0 @ 20.0) ),
15 | \track, Pseq( (0..7), inf )
16 | );
17 | z = y.play( protoEvent: x.asProtoEvent );
18 | /*
19 | y.asUScore( x ).gui; // generate a score
20 | */
21 | )
22 |
23 | ( // fast jazz
24 | z.stop;
25 | y = Pbind(
26 | \dur, 0.1,
27 | \fadeOut, Pwhite( 0.0, 0.1 ),
28 | \legato, Pwhite( 0.5, 2),
29 | \formant, Pwhite( 0.0,1).linexp(0,1,110,1000),
30 | \degree, Prand( (1..9).collect({ |item|
31 | Pseries(0, 2, item) - 6
32 | }), inf ),
33 | \root, Pstutter( Pwhite( -6, 6 ), Pwhite( 12, 24 ) ),
34 | \point, Pwhite( (-20.0 @ -20.0), (20.0 @ 20.0) ),
35 | \track, Pseq( (0..7), inf )
36 | );
37 | z = y.play( protoEvent: x.asProtoEvent );
38 | /*
39 | y.asUScore( x ).gui; // generate a score
40 | */
41 | )
42 |
43 | ( // can your system handle this?
44 | z.stop;
45 | y = Pbind(
46 | \dur, Pwhite( 0.01, 0.02 ),
47 | \legato, 8,
48 | \formant, Pbrown( 0.0,1, 0.05).linexp(0,1,220,1500),
49 | \freq, Pwhite( 220.0, 440.0 ),
50 | \point, Pwhite( (-20.0 @ -20.0), (20.0 @ 20.0) )
51 | );
52 | z = y.play( protoEvent: x.asProtoEvent );
53 | /*
54 | y.asUScore( x, 200 ).cleanOverlaps.gui; // generate a score
55 | */
56 | )
57 |
58 | z.stop;
--------------------------------------------------------------------------------
/Examples/code examples/VBAP.scd:
--------------------------------------------------------------------------------
1 |
2 | Udef.defsFolders.add(WFSArrayPan.filenameSymbol.asString.dirname +/+ "UnitDefs");
3 |
4 | VBAPLib.startup;
5 |
6 | VBAPSpeakerConf.default = VBAPSpeakerConf.fivePointOne;
7 |
8 | //one can also just write the files to disk and not have to run this line again
9 | VBAPSynthDef.generateDefs(5).do(_.send(ULib.servers));
10 |
11 | //run this only once
12 | VBAPSpeakerConf.default.sendBuffer(ULib.servers);
13 |
14 |
15 |
16 |
17 | x = UChain(\blip, \wfsPathPlayer, [\vbap2D_Panner, [\pointFromBus, true]]);
18 | x.prepareAndStart;
19 | x.gui
--------------------------------------------------------------------------------
/Examples/code examples/creating a FreeUdef.scd:
--------------------------------------------------------------------------------
1 | // create a FreeUdef similar to the \sine Udef
2 | (
3 | d = FreeUdef( \testFree, [ \freq, 440, \amp, 0.1 ] )
4 | .createSynthFunc_({ |unit, target|
5 | Synth( "u_testFree", unit.getArgsFor( target ), target, \addToTail );
6 | })
7 | .setSynthFunc_({ |unit ...keyValuePairs|
8 | unit.synths.do{ |s|
9 | var server = s.server;
10 | s.set(*keyValuePairs.clump(2).collect{ |arr|
11 | [arr[0],arr[1].asControlInputFor(server)] }.flatten)
12 | };
13 | })
14 | .addUIO( UOut, \ar, 0, { Silent.ar } )
15 | .synthDef_(
16 | SynthDef( "u_testFree", { |freq = 440, amp = 0.1|
17 | UOut.ar( 0, SinOsc.ar( freq, 0, amp ) );
18 | })
19 | )
20 | )
21 |
22 | d.args;
23 | d.audioOuts; // show the outputs
24 |
25 | x = UChain( \testFree, \wfsSource ); // make a chain
26 | x.gui;
27 |
28 | (
29 | // no setSynthFunc (fallback to Udef:setSynth)
30 | d = FreeUdef( \testFree, [ \freq, 440, \amp, 0.1 ] )
31 | .createSynthFunc_({ |unit, target|
32 | Synth( "u_testFree", unit.getArgsFor( target ), target, \addToTail );
33 | })
34 | .addUIO( UOut, \ar, 0, { Silent.ar } )
35 | .synthDef_(
36 | SynthDef( "u_testFree", { |freq = 440, amp = 0.1|
37 | UOut.ar( 0, SinOsc.ar( freq, 0, amp ) );
38 | })
39 | )
40 | )
41 |
42 | (
43 | // no createSynthFunc either (fallback to Udef:createSynth)
44 | // only args, UIO and a synthDef are really needed
45 | d = FreeUdef( \testFree, [ \freq, 440, \amp, 0.1 ] )
46 | .addUIO( UOut, \ar, 0, { Silent.ar } )
47 | .synthDef_(
48 | SynthDef( "u_testFree", { |freq = 440, amp = 0.1|
49 | UOut.ar( 0, SinOsc.ar( freq, 0, amp ) );
50 | })
51 | )
52 | )
53 |
54 | (
55 | // most basic version:
56 | d = FreeUdef( \testFree )
57 | .synthDef_(
58 | SynthDef( "u_testFree", { |freq = 440, amp = 0.1|
59 | UOut.ar( 0, SinOsc.ar( freq, 0, amp ) );
60 | })
61 | )
62 | .addSynthDefControls;
63 |
64 | )
65 |
--------------------------------------------------------------------------------
/Examples/code examples/generatig session.scd:
--------------------------------------------------------------------------------
1 | (
2 | f = { 12.collect({ |i|
3 | var evt;
4 | evt = UChain(i/2,i+1,rrand(3.0,10.0),false,\sine, \wfsSource).fadeOut_(1).fadeIn_(1);
5 | evt.units[0].set(\freq,rrand(200.0,600.0) );
6 | evt.units[1].set(\point, rrand(-5.0,5.0)@rrand(-5.0,5.0));
7 | evt;
8 | }) };
9 | z = UScore(*(12.collect({ |i|
10 | var evt;
11 | evt = BufSndFile("@resources/sounds/a11wlk01-44_1.aiff",
12 | rate: (i-6).midiratio, loop: [true,false].wrapAt(i) ).makeUChain( \wfsSource )
13 | .releaseSelf_(true).startTime_(i/2).track_(i).fadeOut_(1).fadeIn_(1);
14 |
15 | if( evt.duration == inf ) {
16 | evt.duration = 8; // looped events stopped by UScore
17 | };
18 | evt;
19 | })++f.()++[
20 | UScore(*f.()++[
21 | UScore(*f.())
22 | ]
23 | )]));
24 | z.cleanOverlaps;
25 | x = USession(z,
26 | UChain(\sine,\wfsSource),
27 | UChain(\sine,\wfsSource),
28 | UChain(\sine,\wfsSource),
29 | UChain(\sine,\wfsSource),
30 | UChainGroup(
31 | UChain([\sine,[\freq,200]],\wfsSource),
32 | UChain([\sine,[\freq,400]],\wfsSource)
33 | )
34 | );
35 | x.gui;
36 | )
--------------------------------------------------------------------------------
/Examples/code examples/generating lots of events score.scd:
--------------------------------------------------------------------------------
1 | // the code below generates the 'lots of events.uscore' example score
2 |
3 | x = UScore(
4 | *200.collect({
5 | UChain(10 - (0.5 exprand: 10),
6 | [ \formant, [
7 | \freq, (40 rrand: 100).midicps,
8 | \formant, (60 rrand: 120).midicps,
9 | ] ],
10 | [ \wfsSource, [ \point, (20.0 @ 20.0).rand2 ] ]
11 | ).duration_( 0.1 rrand: 0.3 ).fadeOut_( 0.0 rrand: 1.0 );
12 | }).sort
13 | ).cleanOverlaps;
14 | x.gui;
--------------------------------------------------------------------------------
/Examples/code examples/generating scores.scd:
--------------------------------------------------------------------------------
1 |
2 | //harmonic
3 | //long
4 | (
5 | f = 60.collect({ |i| // generate 60 UChains
6 | var evt;
7 | var start = rrand(0.0,10.0);
8 | var dur = rrand(0.1,3.0);
9 | evt = UChain(start,0,dur,\pulse, \wfsSource).fadeOut_(0.1*dur).fadeIn_(0.1*dur);
10 | evt.units[0].set(\freq,100*rrand(1,10).postln );
11 | evt.units[1].set(\point, rrand(-5.0,5.0)@rrand(-5.0,5.0));
12 | evt;
13 | });
14 | x = UScore(*f).cleanOverlaps; // put them in a score, cleanup overlapping tracks
15 | x.gui;
16 |
17 | )
18 | //short
19 | (
20 | f = 120.collect({ |i|
21 | var evt;
22 | var start = rrand(0.0,10.0);
23 | var dur = rrand(0.1,0.5);
24 | evt = UChain(start,0,dur,\pulse, \wfsSource ).fadeOut_(0.1*dur).fadeIn_(0.1*dur);
25 | evt.units[0].set(\freq, 100*rrand(1,15) );
26 | evt.units[1].set(\point, rrand(-5.0,5.0)@rrand(-5.0,5.0));
27 | evt;
28 | });
29 | x = UScore(*f).cleanOverlaps;
30 | x.gui;
31 |
32 | )
33 |
34 | //long
35 | (
36 | f = 60.collect({ |i|
37 | var evt;
38 | var start = rrand(0.0,10.0);
39 | var dur = rrand(0.1,3.0);
40 | evt = UChain(start,0,dur,\pulse, \wfsSource ).fadeOut_(0.1*dur).fadeIn_(0.1*dur);
41 | evt.units[0].set(\freq, rrand(100.0,600.0) );
42 | evt.units[1].set(\point, rrand(-5.0,5.0)@rrand(-5.0,5.0));
43 | evt;
44 | });
45 | x = UScore(*f).cleanOverlaps;
46 | x.gui;
47 |
48 | )
49 | //short
50 | (
51 | f = 120.collect({ |i|
52 | var evt;
53 | var start = rrand(0.0,10.0);
54 | var dur = rrand(0.1,0.5);
55 | evt = UChain(start,0,dur,\pulse, \wfsSource ).fadeOut_(0.1*dur).fadeIn_(0.1*dur);
56 | evt.units[0].set(\freq, rrand(100.0,600.0) );
57 | evt.units[1].set(\point, rrand(-5.0,5.0)@rrand(-5.0,5.0));
58 | evt;
59 | });
60 | x = UScore(*f).cleanOverlaps;
61 | x.gui;
62 |
63 | )
64 |
--------------------------------------------------------------------------------
/Examples/code examples/import v1 WFSPathArray xml.scd:
--------------------------------------------------------------------------------
1 | // this file demonstrates how to import an xml file with trajectory
2 | // data from WFSCollider version 1
3 |
4 | (
5 | Dialog.openPanel({ |file|
6 | var array;
7 | array = WFSPathArray.readWFSFile( file );
8 | UScore( *array.collect({ |path, i|
9 | UChain( 0, i, path.length, \bufSoundFile, [ \wfsSource, [
10 | \point, UMap( \trajectory, [
11 | \trajectory, WFSPathBuffer( path.asWFSPath2 ) ] ),
12 | \distanceFilter, 1
13 | ]
14 | ] )
15 | }) ).gui;
16 | });
17 | )
--------------------------------------------------------------------------------
/Examples/code examples/mass editing.scd:
--------------------------------------------------------------------------------
1 | // MassEditU:
2 |
3 | // create 10 similar units
4 | y = 10.collect({ U( \sine, [ \freq, 220 rrand: 880, \amp, 0.1 rrand: 0.5 ] ) });
5 |
6 | // show them all in a window
7 | w = Window("mass-edit", Rect(571, 101, 264, 381)).front;
8 | w.addFlowLayout;
9 | y.do(_.gui(w));
10 |
11 | // create a mass editor
12 | z = MassEditU( y );
13 | z.gui;
14 |
15 |
16 | // MassEditUChain
17 |
18 | // create 10 similar uchains
19 | (
20 | y = 10.collect({ |i|
21 | UChain(
22 | [
23 | [ \sine, [ \freq, 220 rrand: 880, \amp, 0.1 rrand: 0.5 ] ],
24 | [ \whiteNoise, [ \amp, 0.1 rrand: 0.5 ] ]
25 | ].choose,
26 | [ \wfsSource, [ \point, (10.0@10.0).rand2 ] ]
27 | )
28 | .track_(i)
29 | .dur_( 2 rrand: 10 )
30 | .setGain( -10 rrand: 10 );
31 | });
32 |
33 | a = UScore(*y);
34 |
35 | )
36 |
37 | // show them all in a window
38 | a.gui;
39 |
40 | // create a mass editor
41 | z = MassEditUChain( y );
42 | z.gui;
43 |
--------------------------------------------------------------------------------
/Examples/code examples/path editor control.scd:
--------------------------------------------------------------------------------
1 | // WFSPathGUI is a plotting and editing view for WFSPath2 objects
2 |
3 | a = WFSPathGUI();
4 |
5 | // modify zoom settings
6 | a.zoomToFit;
7 | a.zoom( 2 );
8 | a.zoom; // reset
9 | a.move(-1,10);
10 | a.move; // reset
11 |
12 | // selection from code
13 | a.select( 1, 2, 6 );
14 | a.selectAll;
15 | a.selectNone;
16 |
17 | // edit from code (can also do by mouse)
18 | a.moveSelected( 2, -2, ModKey(0) );
19 | a.scaleSelected( 0.5, -0.75 );
20 | a.rotateSelected( 0.125pi, 1.25 ); // rotate and scale
21 |
22 | // mouse modes
23 | a.mouseMode = \select; // default, also edit
24 | a.mouseMode = \zoom; // zoom in/out, double-click for zoomToFit
25 | a.mouseMode = \move; // move canvas, double-click for centered
26 | a.mouseMode = \record; // record a path (resets to \select after mouseUp)
27 |
28 | // mouse edit modes
29 | // these only work when mouseMode == \select
30 | a.editMode = \move;
31 | a.editMode = \scale;
32 | a.editMode = \rotate;
33 | a.editMode = \rotateS;
34 | a.editMode = \elastic;
35 | a.editMode = \lock; // editing disabled
36 |
37 |
38 | // position display and animation
39 | a.pos = 0.25; // show time position
40 | a.pos = nil;
41 |
42 | a.animate( true ); // animation
43 | a.animate( false );
44 |
45 | a.animationRate = 0.25; // slow down
46 | a.animationRate = 1; // normal speed
47 |
48 | // undo
49 | a.undo; // go to previous state
50 | a.undo(-1); // go to next state (if available)
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Examples/code examples/point constellations.scd:
--------------------------------------------------------------------------------
1 | // below is code for generating groups of moving or static points
2 |
3 | (
4 | // circle
5 | n = 12; // number of events
6 | r = 8; // radius
7 | a = UScore(
8 | *n.collect({ |i|
9 | UChain(0, i,
10 | [ \formant, [
11 | \freq, 50.0 rrand: 60,
12 | \formant, 100 exprand: 1000,
13 | ] ],
14 | [ \tremolo, [ \speed, (i*3/n) ] ],
15 | [ \wfsSource, [ \point, Polar(r, i.linlin(0,n,0,2pi) ).asPoint ] ]
16 | ).duration_( 10 ).fadeOut_( 1 );
17 | })
18 | );
19 | a.gui;
20 | )
21 |
22 |
23 | (
24 | // moving circle (check the WFSPositionTracker)
25 | n = 12; // number of events
26 | r = 8; // radius
27 | b = UScore(
28 | *n.collect({ |i|
29 | UChain(0, i,
30 | [ \formant, [
31 | \freq, 100.0 rrand: 120,
32 | \formant, 130 exprand: 1200,
33 | ] ],
34 | [ \wfsSource, [ \point, [ \circle_trajectory, [
35 | \speed, 0.1,
36 | \startAngle, i.linlin(0,n,-pi,pi),
37 | \radius, r@r
38 | ] ]
39 | ] ]
40 | ).duration_( 10 ).fadeOut_( 1 );
41 | })
42 | );
43 | b.gui;
44 | )
45 |
46 | (
47 | // swarm
48 | n = 12; // number of events
49 | r = 12; // radius
50 | c = UScore(
51 | *n.collect({ |i|
52 | UChain(0, i,
53 | [ \formant, [
54 | \freq, 600.0 rrand: 1000,
55 | \formant, 1400 exprand: 2000,
56 | ] ],
57 | [ \wfsSource, [ \point, [ \random_trajectory, [
58 | \speed, 0.7,
59 | \radius, r@r,
60 | \seed, 1234,
61 | \center, [ \random_trajectory, [
62 | \speed, 2,
63 | \radius, 2@2,
64 | ] ]
65 | ] ]
66 | ] ]
67 | ).duration_( 10 ).fadeOut_( 1 ).gain_( -6 );
68 | })
69 | );
70 | c.gui;
71 | )
72 |
73 | (
74 | // line
75 | n = 12; // number of events
76 | p = -8 @ -8; // start point
77 | q = 8 @ 8; // end point
78 | d = UScore(
79 | *n.collect({ |i|
80 | UChain(0, i,
81 | [ \formant, [
82 | \freq, (44 + (i*2)).midicps,
83 | \formant, 100 exprand: 1000,
84 | ] ],
85 | [ \tremolo, [ \speed, i.linlin(0,n-1,0.5,1.5), \smooth, 0.05 ] ],
86 | [ \wfsSource, [ \point, i.linlin( 0@0, (n-1)@(n-1), p, q ) ] ]
87 | ).duration_( 10 ).fadeOut_( 1 );
88 | })
89 | );
90 | d.gui;
91 | )
92 |
93 | (
94 | // rotating line
95 | n = 12; // number of events
96 | r = 8; // radius
97 | e = UScore(
98 | *n.collect({ |i|
99 | UChain(0, i,
100 | [ \formant, [
101 | \freq, 160.0 rrand: 280,
102 | \formant, 280 exprand: 2000,
103 | ] ],
104 | [ \wfsSource, [ \point, [ \circle_trajectory, [
105 | \speed, 0.1,
106 | \startAngle, if( i < (n/2) ) { 0 } { pi },
107 | \radius, i.linlin(0,n-1,r.neg,r).abs.asPoint
108 | ] ]
109 | ] ]
110 | ).duration_( 10 ).fadeOut_( 1 );
111 | })
112 | );
113 | e.gui;
114 | )
115 |
116 | (
117 | // all scores together in one:
118 | UScore(
119 | a.name_( "circle" ),
120 | b.name_( "moving circle" ).startTime_(10).track_(1),
121 | c.name_( "swarm" ).startTime_(20),
122 | d.name_( "line" ).startTime_(30).track_(1),
123 | e.name_( "rotating line" ).startTime_(40),
124 | ).gui;
125 | )
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/Examples/code examples/score playback control 1.scd:
--------------------------------------------------------------------------------
1 | //play 3 seconds and stop by itself
2 | (
3 | z = UScore( UChain(0,0,3,\sine, \wfsSource ).fadeOut_(1).fadeIn_(1) );
4 | y = z.gui;
5 | fork{
6 | z.prepareAndStart(ULib.servers,0);
7 | }
8 | )
9 |
10 |
11 | //play 3.5 seconds and stop;
12 | (
13 | z = UScore( UChain(0,0,10,\sine, \wfsStaticPoint).fadeOut_(1).fadeIn_(1) );
14 | y = z.gui;
15 | fork{
16 | z.prepareAndStart(ULib.servers,0);
17 | 0.5.wait;
18 | if(z.isPlaying != true){ "error ! isPlaying should be true".throw };
19 | 3.wait;
20 | z.stop;
21 | if(z.isPlaying != false){ "error ! isPlaying should be false".throw };
22 | }
23 | )
24 |
25 | //play 3 seconds and pause for 1 seconds then stop;
26 | //note that the pause will not stop the chain from playing, but does halt the timeline
27 | (
28 | z = UScore( UChain(0,0,10,\sine, \wfsStaticPoint).fadeOut_(1).fadeIn_(1) );
29 | y = z.gui;
30 | fork{
31 | z.prepareAndStart(ULib.servers,0);
32 | 3.wait;
33 | z.pause;
34 | if(z.isPaused != true){ "error ! isPaused should be true".throw };
35 | 1.wait;
36 | z.stop;
37 | }
38 | )
39 |
40 | // should play 2 tones, the lower tone stop after 5 seconds, the hight tone stops after 8 seconds
41 | // 'releaseSelf' for the first UChain is set to false, which means that the score timeline
42 | // decides when the event stops.
43 | (
44 | r = UChain(0,0,5,false,[\sine, [\freq, 956]], \wfsSource).fadeOut_(1).fadeIn_(1);
45 | v = UChain(0,1,5,true, [\sine, [\freq, 400]], \wfsSource).fadeOut_(1).fadeIn_(1);
46 | z = UScore(r,v);
47 | y = z.gui;
48 | fork{
49 | z.prepareAndStart(ULib.servers,0);
50 | 3.wait;
51 | z.pause;
52 | if(z.isPaused != true){ "error ! isPaused should be true".throw };
53 | 3.wait;
54 | z.resume;
55 | if(z.isPaused != false){ "error ! isPaused should be true".throw };
56 | }
57 | )
58 |
59 | // play some sound files.
60 | // the looped files will become infinite duration events, which are only stopped when the
61 | // score ends
62 | (
63 | z = UScore(
64 | *12.collect({ |i|
65 | BufSndFile("@resources/sounds/a11wlk01-44_1.aiff",
66 | rate: (i-6).midiratio, loop: [true,false].wrapAt(i) ).makeUChain( \wfsSource )
67 | .startTime_(i/2).track_(i).fadeOut_(1).fadeIn_(1);
68 | })
69 | );
70 | y = z.gui;
71 | z.prepareAndStart;
72 | )
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Examples/code examples/score playback control 2.scd:
--------------------------------------------------------------------------------
1 | (
2 | // create a score with soundfiles
3 | z = UScore(
4 | *12.collect({ |i|
5 | var evt;
6 | evt = BufSndFile("@resources/sounds/a11wlk01-44_1.aiff",
7 | rate: (i-6).midiratio, loop: [true,false].wrapAt(i) ).makeUChain( \wfsSource )
8 | .releaseSelf_(true).startTime_(i/2).track_(i).fadeOut_(1).fadeIn_(1);
9 |
10 | if( evt.duration == inf ) {
11 | evt.duration = 8; // looped events limited to 8s
12 | };
13 | evt;
14 | })
15 | );
16 | y = z.gui;
17 | )
18 |
19 | (
20 | // create a score with sine waves
21 | z = UScore(
22 | *12.collect({ |i|
23 | var evt;
24 | evt = UChain(i/2,i,rrand(3.0,10.0),\sine, \wfsSource).fadeOut_(1).fadeIn_(1);
25 | evt.units[0].set(\freq,rrand(200.0,600.0) );
26 | evt;
27 | })
28 | );
29 | y = z.gui;
30 | )
31 |
32 |
33 | z.prepare( s, 0, { "done".postln } );
34 | z.start( s, 0, true );
35 |
36 | z.pause; // looped events keep playing
37 | z.resume;
38 |
39 | z.stop;
40 |
41 | z.start( s, 0, false ); // takes extra wait time for preparing events (depends on content)
42 |
43 | z.pos; // returns current position (keeps increasing if not stopped
--------------------------------------------------------------------------------
/Examples/code examples/speaker test generator.scd:
--------------------------------------------------------------------------------
1 | // The code below generates a series of test signals for each speaker of
2 | // the currently active setup. In the default settings this generates
3 | // short pink noise bursts, twice on each group of 8 speakers.
4 |
5 | (
6 | n = 8; // size of speaker groups
7 | z = 1/4; // duration per burst
8 | t = \pinkNoise; // udef name for sound generation
9 | r = 2; // number of repeats per group
10 | x = UScore();
11 |
12 | (WFSSpeakerConf.default.speakerCount / n).ceil.do({ |i|
13 | var folder;
14 | folder = UScore( i * (r * (n + 1) * z) );
15 | x.add( folder );
16 | r.do({ |ii|
17 | n.do({ |iii|
18 | folder.add( UChain( ((ii * (n + 1)) + iii) * z, iii, z * (3/4),
19 | [ t, [ \seed, 12345 ] ],
20 | [ \wfsIndex, [ \index, (i * 8) + iii, \gain, 0 ] ]
21 | )
22 | );
23 | });
24 | });
25 | folder.name = ([1,n] + (i*8)).join("-");
26 | });
27 |
28 | x.gui;
29 | )
--------------------------------------------------------------------------------
/Examples/code examples/touchosc example.scd:
--------------------------------------------------------------------------------
1 | // load the "touchosc wfs" scene (in this folder) to your touchosc device, and play
2 |
3 | NetAddr.langPort.postln; // make sure your touchosc device talks to this port
4 |
5 | (
6 | UScore(
7 | UChain(
8 | 'whiteNoise',
9 | [ 'cutFilter', [ 'freq', [ 20, 800 ] ] ],
10 | [ 'tremolo', [ 'speed', 5 ] ],
11 | [ 'wfsSource', [ 'point', 'lag_point' ] ]
12 | ).fadeIn_(1).fadeOut_(1)
13 | ).gui;
14 | )
15 |
16 | UScore.current.enableOSC; // or check the 'OSC' button in the gui
17 |
18 | // manual controls (more than the touchosc patch can do)
19 |
20 | y = NetAddr( "127.0.0.1", NetAddr.langPort );
21 |
22 | // setting point x and y
23 | y.sendMsg( '/untitled/0/3/point/point.x', 5);
24 | y.sendMsg( '/untitled/0/3/point/point.y', -10);
25 |
26 | // setting the whole point
27 | y.sendMsg( '/untitled/0/3/point/point', 10, 5);
28 |
29 | // start and stop the score
30 | y.sendMsg( '/untitled/prepareAndStart');
31 | y.sendMsg( '/untitled/stop');
32 |
33 | // setting the amp for the whiteNoise (first) unit
34 | y.sendMsg( '/untitled/0/0/amp', 0.125 );
35 | y.sendMsg( '/untitled/0/0/amp' , 0.5 );
36 |
37 | y.sendMsg( '/untitled/0/0/amp' , \lfo_sine ); // apply an UMap
38 | y.sendMsg( '/untitled/0/0/amp' , 0.1 ); // remove it again
39 |
40 | // control the chain playback individually
41 | y.sendMsg( '/untitled/0/stop' );
42 | y.sendMsg( '/untitled/0/prepareAndStart' );
43 | y.sendMsg( '/untitled/0/release' );
44 |
45 | UScore.current.disableOSC;
--------------------------------------------------------------------------------
/Examples/code examples/touchosc wfs.touchosc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/Examples/code examples/touchosc wfs.touchosc
--------------------------------------------------------------------------------
/Examples/code examples/udefs and io.scd:
--------------------------------------------------------------------------------
1 | (
2 | // create some Udefs
3 |
4 | Udef( \mix2, { |balance = 0.5| // mix two inputs together
5 | var l1, l2;
6 | l1 = UIn.ar( 0 ) * (1-balance);
7 | l2 = UIn.ar( 1 ) * balance;
8 | UOut.ar( 0, l1 + l2 )
9 | } );
10 |
11 | Udef( \vibrato, { |rate = 1, amount = #[0.0,1.0]| // a tremolo/vibrato
12 | UOut.ar( 0, SinOsc.kr( rate ).range(*amount) * UIn.ar( 0 ) )
13 | } );
14 |
15 | )
16 |
17 | // \sine and \output are already in the Udef bank
18 |
19 | x = UChain( \sine, [ \sine, [ \freq, 550, \u_o_ar_0_bus, 1 ]], \mix2, \vibrato, \wfsSource );
20 |
21 | x.prepareAndStart;
22 | x.release;
23 |
24 | x.fadeOut = 0.5;
25 | x.fadeIn = 0.5;
26 |
27 | x.duration_( 5 );
28 | x.duration_( inf ); // infinite duration (default)
29 |
30 | // change audio outputs
31 | x[0].setAudioOut( 0, 0 );
32 | x[1].setAudioOut( 0, 1 ); // 2nd sine output to bus 1, so it goes to second mix input
33 |
34 | x.gui;
35 |
--------------------------------------------------------------------------------
/Examples/developer tests/LoadBalancer tests.scd:
--------------------------------------------------------------------------------
1 | (
2 | ~lbs = 2.collect({ |i|
3 | LoadBalancer( *WFSServers.default.multiServers[i].servers );
4 | });
5 |
6 | ULib.servers = [ s ] ++ ~lbs;
7 |
8 | UChain.defaultServers = [ s ] ++ ~lbs;
9 | )
10 |
11 | (
12 | thisThread.randSeed = 12345;
13 | r = 120.collect({ |i|
14 | UChain(rrand(0.5,2.0),i,2,true,
15 | [\sine,[\freq,rrand(200.0, 1000.0)]],
16 | [ \wfsStaticPoint, [
17 | \point, 10.0.rand2 @ 10.0.rand2,
18 | \dbRollOff, -3
19 | ]
20 | ]
21 | ).fadeOut_(1.75).fadeIn_(0.001);
22 | }).sort;
23 |
24 | z = UScore(*r);
25 | x = UScoreEditor(z);
26 | y = UScoreEditorGUI(x);
27 |
28 | )
29 |
30 |
31 | (
32 |
33 | thisThread.randSeed = 12345;
34 | r = 60.collect({ |i|
35 | UChain( i.linlin(0,60,1,3),i,0.2,true,
36 | [\sine,[\freq,rrand(200.0, 1000.0)]],
37 | [ \wfsStaticPoint, [
38 | \point, 10.0.rand2 @ 10.0.rand2,
39 | \dbRollOff, -3
40 | ]
41 | ]
42 | ).fadeOut_(0.01).fadeIn_(0.01);
43 | }).sort;
44 |
45 | z = UScore(*r);
46 | x = UScoreEditor(z);
47 | y = UScoreEditorGUI(x);
48 |
49 | )
50 |
51 |
52 | (
53 |
54 | thisThread.randSeed = 12345;
55 | r = 10.collect({ |i|
56 | UChain( i.linlin(0,60,1,3),i,2,true,
57 | [\sine,[\freq,rrand(200.0, 1000.0)]],
58 | [ \wfsDynamicPoint, [
59 | \point, 10.0.rand2 @ 10.0.rand2,
60 | \dbRollOff, -3
61 | ]
62 | ]
63 | ).fadeOut_(0.01).fadeIn_(0.01);
64 | }).sort;
65 |
66 | z = UScore(*r);
67 | x = UScoreEditor(z);
68 | y = UScoreEditorGUI(x);
69 |
70 | )
71 |
72 |
73 | (
74 |
75 | ( // speakertest
76 | r = (
77 | 192.collect({ |i|
78 | UChain( i.linlin(0,192,1,26),i%8,0.03,true,
79 | [\sine,
80 | [
81 | \freq, ([ 0, 2, 4, 5, 7, 9, 11, 12 ].reverse[i%8] + 64).midicps
82 | ]
83 | ],
84 | [ \wfsStaticIndex, [ \index, i.asInteger ] ]
85 | ).fadeOut_(0.02);
86 | }) ++ (((..23) * 8) + 3).collect({ |i|
87 | UChain( i.linlin(0,192,1,26),8,0.5,true,
88 | [\sine, [ \freq, 60] ],
89 | [ \wfsStaticIndex, [ \index, i.asInteger ] ]
90 | ).fadeIn_(0).fadeOut_(0.45);
91 | })
92 | ).sort;
93 | );
94 |
95 | z = UScore(*r);
96 | x = UScoreEditor(z);
97 | y = UScoreEditorGUI(x);
98 |
99 | )
100 |
101 | (
102 | ( // random rhythm
103 | a = [ 0, 2, 4, 5, 7, 9, 11, 12 ].scramble;
104 | r = (
105 | 192.collect({ |i|
106 | UChain( i.linlin(0,192,1,26),i%8,0.2,true,
107 | [ \sine, [
108 | \freq, (a[i%8] + 64).midicps
109 | ]
110 | ],
111 | [ \wfsStaticPoint,[
112 | \point, 20.0.rand2 @ 20.0.rand2,
113 | \latencyComp, 1,
114 | \dbRollOff, 0
115 | ]
116 | ]
117 | ).fadeIn_(0.1).fadeOut_(0.01);
118 | })
119 | ).sort;
120 | );
121 |
122 | z = UScore(*r);
123 | x = UScoreEditor(z);
124 | y = UScoreEditorGUI(x);
125 |
126 | )
127 |
128 | LoadBalancer.all.collect(_.loads);
129 | // should be [ [ 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0 ] ]
130 |
131 | LoadBalancer.all.collect(_.reset);
132 |
--------------------------------------------------------------------------------
/Examples/developer tests/Spec guis test.scd:
--------------------------------------------------------------------------------
1 |
2 | // Show all types of spec
3 | (
4 | x = Udef(\test,{ |bus = 0, freq = 500,thing2=1, thing3 =1,thing4,thing5,thing6|
5 | Out.ar(bus,WhiteNoise.ar*0.001*\point.kr(0,0)) },
6 | [[\bus,0,IntegerSpec()],
7 | [\point, Point(1,2),PointSpec(Rect(0,0,20,20))], // is not constraining...
8 | [\thing2,1,BoolSpec()],
9 | [\thing3,1,ListSpec([1,2,3,4],2)],
10 | //[\thing4,1,RangeSpec()] this is broken
11 | ]);
12 | y = U(\test);
13 | y.gui;
14 | )
15 |
16 | RangeSpec()
17 |
18 | //EQ
19 |
20 | (
21 | var numChannels = 2;
22 | x = MetaU(\param_beq,[\numChannels,numChannels],[\eq_controls,EQSpec().default]);
23 | y = Udef(\noise,{ UOut.ar(0, WhiteNoise.ar.dup(numChannels) *0.1) });
24 | r = MetaU(\copy,[\numChannels,numChannels]);
25 | z = UChain(\noise,x,r);
26 | z.prepareAndStart(s);
27 | x.unit.gui(nil,Rect(0,0,700,700))
28 | )
29 |
30 | x.set(\eq_controls,EQArg([ [ 100, 0, 1 ], [ 250, 0, 1 ], [ 1000, 0, 1 ], [ 3500, 0, 1 ], [ 10000, -24, 1 ] ]))
31 |
--------------------------------------------------------------------------------
/Examples/developer tests/Test FilePlayers 0.1.scd:
--------------------------------------------------------------------------------
1 | //run this first
2 | Udef.loadAllFromDefaultDirectory.do(_.loadSynthDef(s));
3 |
4 | // example
5 | ~path = "sounds/a11wlk01-44_1.aiff";
6 |
7 | //buffer
8 | //not looped
9 | x = BufSndFile(~path);
10 | //looped
11 | x = BufSndFile(~path, startFrame: 44100*0.2, rate:1.5, loop: true);
12 |
13 | x.postcs; "";
14 | //disk
15 | x = DiskSndFile(~path, startFrame: 44100*0.1, endFrame:44100*2);
16 | //looped (infinite duration)
17 | x = DiskSndFile(~path, loop: true);
18 |
19 | //play
20 | (
21 | y = x.makeUnit;
22 | z = UChain(y,\output);
23 | z.useSndFileDur; // use duration
24 | z.prepareAndStart(s);
25 | )
26 |
27 | // or shorter:
28 | (
29 | z = x.makeUChain;
30 | z.prepareAndStart(s);
31 | )
32 |
33 | z.release(0.5); // release of 0.5s (for looping variants)
34 |
35 | // play while keeping buffers
36 | (
37 | z = x.makeUChain;
38 | z[0].disposeOnFree = false;
39 | z.prepare(s);
40 | )
41 |
42 | z.start(s); // as many times as you want
43 |
44 | z.release; // stop all
45 |
46 | z.dispose(s); // frees all active buffers
47 |
48 | //this should be empty when nothing is playing or after dispose
49 | z[0].get(\soundFile).buffers;
50 |
51 |
52 | // this will create Chain, allocate buffer, play, and when finished, free the buffer.
53 | z = x.play(s);
54 |
55 | z.gui;
56 |
57 | x.plot
58 |
59 | //RichBuffer
60 | (
61 | Udef(\testBuffer,{ |buf|
62 | Out.ar(0,BufAllpassN.ar(buf, Decay.ar(Dust.ar(1,0.5), 0.2, WhiteNoise.ar), 0.2, 3) )
63 | });
64 | x = U(\testBuffer,[\buf,RichBuffer(44100*1)]);
65 | x.prepareAndStart(s);
66 | )
67 |
68 | x.get( \buf ).buffers; // try again after stop
69 |
70 | x.stop;
71 |
--------------------------------------------------------------------------------
/Examples/developer tests/VBAP.scd:
--------------------------------------------------------------------------------
1 |
2 | //2D
3 | (
4 | //startup
5 | Udef.defsFolders.add(
6 | WFSArrayPan.filenameSymbol.asString.dirname +/+ "UnitDefs"
7 | );
8 | VBAPLib.startup;
9 | VBAPSpeakerConf.default = VBAPSpeakerConf( (4.collect{ |i| (-45/2) - (45 * i) } +++ 4.collect{ |i| (45/2) + (45 * i) }).flatten );
10 | VBAPSpeakerConf.default.makeBuffer;
11 | Udef.loadAllFromDefaultDirectory;
12 | UMenuBar();
13 | )
14 |
15 | UChain(\blip, \vbap2D_Simple_Panner).gui
16 | UChain(\blip, U(\wfsPathPlayer), U(\vbap2D_Panner).pointFromBus_(true)).gui
17 |
18 | //3D
19 | (
20 | //startup
21 | //Sonic Lab
22 | x = [ [ 6.31, 0, -25.400967366 ], [ 6.34, 0, 25.9660516833 ], [ 6.67, 0, -67.0576274588 ], [ 6.57, 0, 66.6879780945 ], [ 6.45, 0, -107.4110491464 ], [ 6.46, 0, 107.3832377266 ], [ 7.64, 0, -146.2172414806 ], [ 7.65, 0, 146.1054525865 ], [ 9.6, 0, 0 ], [ 6.35, 0, 180 ], [ 9.22, 17.8750032812, -20.4495476108 ], [ 9.25, 17.8150833255, 20.571247071 ], [ 6.95, 24.0287030727, -65.6744247609 ], [ 6.98, 23.9189613576, 65.6416496995 ], [ 6.75, 24.7878302634, -108.1204280324 ], [ 6.72, 24.906009848, 108.1462414292 ], [ 7.06, 23.6313179834, -155.454155974 ], [ 7.08, 23.5605201117, 155.6036500106 ], [ 6.91, 52.7448792263, -27.5218854663 ], [ 6.9, 52.8541958285, 28.2311587404 ], [ 6.49, 57.9362142825, -74.594892688 ], [ 6.41, 59.0965878748, 73.451059145 ], [ 6.55, 57.1078901345, -113.1577815608 ], [ 6.6, 56.4426902381, 110.9030667368 ], [ 6.78, 54.2142657891, -151.3671810066 ], [ 6.9, 52.8541958285, 152.046597927 ], [ 6.0084357365, -50.4062940572, -28.0372821602 ], [ 6.0084357365, -50.4062940572, 28.0372821602 ], [ 5.8048083517, -52.9029151782, -77.6309384741 ], [ 5.7349280728, -53.8362268718, 77.1957339347 ], [ 5.9258332747, -51.38202567, -116.4957697362 ], [ 5.9035836574, -51.6531568981, 116.7749248886 ], [ 6.0235952719, -50.2322714936, -159.9660768355 ], [ 6.0655832366, -49.7580403359, 157.4926118991 ] ];
23 | y = x.flop[1..].swap(0,1).flop;
24 | z = x.collect(_[0]);
25 |
26 | ~sonicLab = VBAPSpeakerConf(y,z);
27 | Udef.defsFolders.add(
28 | WFSArrayPan.filenameSymbol.asString.dirname +/+ "UnitDefs"
29 | );
30 | VBAPLib.startup;
31 | VBAPSpeakerConf.default = ~sonicLab;
32 | VBAPSpeakerConf.default.makeBuffer;
33 | Udef.loadAllFromDefaultDirectory;
34 | UMenuBar();
35 | )
36 |
37 | UChain(\blip, \vbap3D_Simple_Panner).gui;
38 | UChain(\blip, \vbap3D_Panner).gui
--------------------------------------------------------------------------------
/Examples/developer tests/sample sched simple test case - supernova.scd:
--------------------------------------------------------------------------------
1 | //supernova version
2 |
3 | (
4 | Server.program = "cd % && exec ./supernova -D 1 -U plugins".format(String.scDir.quote);
5 |
6 | ~soptions = ServerOptions()
7 | .memSize_(8192*12)
8 | .numAudioBusChannels_(150)
9 | .numOutputBusChannels_(2)
10 | .numInputBusChannels_(30)
11 | .numWireBufs_(2048)
12 | .sampleRate_( 44100 )
13 | .blockAllocClass_( ContiguousBlockAllocator )
14 | .blockSize_( 512 );
15 | //.device_("JackRouter");
16 |
17 | ~slaves = [
18 | Server(\slave1,NetAddr("localhost", 57456),~soptions),
19 | Server(\slave2,NetAddr("localhost", 57458),~soptions)
20 | ];
21 |
22 | ~master = Server(\master,NetAddr("localhost", 57368),~soptions);
23 |
24 | (~slaves++[~master]).do(_.makeWindow);
25 |
26 | SyncCenter.inBus = 0;
27 | SyncCenter.outBus = 0;
28 | SyncCenter.addAll(~slaves);
29 | SyncCenter.master_(~master);
30 |
31 |
32 | {
33 | ~master.boot;
34 | 2.wait;
35 | ~slaves[0].boot;
36 | 2.wait;
37 | ~slaves[1].boot;
38 |
39 | while({ ~master.serverBooting || ~slaves[0].serverBooting || ~slaves[1].serverBooting }) {
40 | 1.wait;
41 | };
42 | "servers booted".postln;
43 |
44 | "jack_connect supernova:output_1 supernova-01:input_1 &&
45 | jack_connect supernova:output_1 supernova-02:input_1 &&
46 | jack_connect supernova-01:output_1 system:playback_1 &&
47 | jack_connect supernova-02:output_1 system:playback_1".runInTerminal;
48 |
49 | SyncCenter.sendDefs;
50 |
51 |
52 | }.fork;
53 |
54 | )
55 | //turns on more posting of info
56 | SyncCenter.verbose = true
57 | //do the remote sync between all servers
58 | SyncCenter.remoteSync;
59 | //after multiple remoteSync the values outputed by this should always be hte same
60 | SyncCenter.serverCounts.collect{ |x| x.value - SyncCenter.current.localCount }
61 |
62 |
63 | //canceling sine-waves
64 | //if the sync is working then these two sinewaves will cancel.
65 | ~slaves.do({ arg server;
66 | SynthDef("sine", { arg out=0, freq=110.0, amp=0.1;
67 | OffsetOut.ar(out, SinOsc.ar(freq, 0, amp).dup);
68 | }).send(server);
69 | });
70 |
71 |
72 | OSCBundle.new.add([ "/s_new", "sine", 2000, 1, 1, 'freq', 1000, 'amp', 0.25 ]).syncedSend(~slaves[0],1);
73 | OSCBundle.new.add([ "/s_new", "sine", 2000, 1, 1, 'freq', 1000, 'amp', -0.25 ]).syncedSend(~slaves[1],1);
74 | //kill slave1 or slave2 and you will hear sine wave again.
75 |
76 | //this number should be the same between syncs
77 | SyncCenter.serverCounts.collect{ |x| x.value - SyncCenter.current.localCount }
78 |
--------------------------------------------------------------------------------
/Examples/developer tests/sample sched simple test case.scd:
--------------------------------------------------------------------------------
1 | // if using supernova (!!!!) run this first:
2 |
3 | Server.program = "cd % && exec ./supernova -U plugins".format(String.scDir.quote);
4 |
5 | //make sure there are no servers running prior to this
6 | //killall scsynth
7 |
8 | (
9 | ~soptions = ServerOptions()
10 | .memSize_(8192*12)
11 | .numAudioBusChannels_(150)
12 | .numOutputBusChannels_(2)
13 | .numInputBusChannels_(30)
14 | .numWireBufs_(2048)
15 | .sampleRate_( 44100 )
16 | .blockAllocClass_( ContiguousBlockAllocator )
17 | .device_("JackRouter");
18 |
19 | ~slaves = [
20 | Server(\slave1,NetAddr("localhost", 57456),~soptions),
21 | Server(\slave2,NetAddr("localhost", 57458),~soptions)
22 | ];
23 |
24 | ~master = Server(\master,NetAddr("localhost", 57368),~soptions);
25 |
26 | (~slaves++[~master]).do(_.makeWindow);
27 |
28 | SyncCenter.inBus = 0;
29 | SyncCenter.outBus = 0;
30 | SyncCenter.addAll(~slaves);
31 | SyncCenter.master_(~master);
32 |
33 |
34 | {
35 | ~master.boot;
36 | 2.wait;
37 | ~slaves[0].boot;
38 | 2.wait;
39 | ~slaves[1].boot;
40 |
41 | while({ ~master.serverBooting || ~slaves[0].serverBooting || ~slaves[1].serverBooting }) {
42 | 1.wait;
43 | };
44 | "servers booted".postln;
45 |
46 | (2.collect{ |i|
47 | "jack_disconnect system:capture_"++(i+1)++" scsynth:in"++(i+1)++" && "++
48 | "jack_disconnect system:capture_"++(i+1)++" scsynth-01:in"++(i+1)++" && "++
49 | "jack_disconnect system:capture_"++(i+1)++" scsynth-02:in"++(i+1)++" && "
50 | }.reduce('++') ++ "jack_connect scsynth:out1 scsynth-01:in1 && jack_connect scsynth:out1 scsynth-02:in1").runInTerminal;
51 |
52 | SyncCenter.sendDefs;
53 |
54 |
55 | }.fork;
56 |
57 | )
58 |
59 | SyncCenter.remoteSync
60 |
61 | ~slaves.do({ arg server;
62 | SynthDef("sine", { arg out=0, freq=110.0, amp=0.1;
63 | OffsetOut.ar(out, SinOsc.ar(freq, 0, amp).dup);
64 | }).send(server);
65 | });
66 |
67 |
68 | OSCBundle.new.add([ "/s_new", "sine", 2000, 1, 1, 'freq', 1000, 'amp', 0.25 ]).syncedSend(~slaves[0],1);
69 | OSCBundle.new.add([ "/s_new", "sine", 2000, 1, 1, 'freq', 1000, 'amp', -0.25 ]).syncedSend(~slaves[1],2);
70 | //kill slave1 or slave2 and you will hear sine wave again.
71 |
72 | //this number should be the same between syncs
73 | SyncCenter.serverCounts.collect{ |x| x.value - SyncCenter.current.localCount }
74 |
--------------------------------------------------------------------------------
/Examples/developer tests/test UScoreEditor rendering.scd:
--------------------------------------------------------------------------------
1 | // 1 event with 10 seconds duration
2 | (
3 | r = UChain(0,0,10,false,[\sine,[\freq,rrand(200.0,500.0)]], \output).fadeOut_(1).fadeIn_(1);
4 | z = UScore(r);
5 | if( z.finiteDuration != 10) { "finiteDuration should be 10".throw };
6 | x = UScoreEditor(z);
7 | y = UScoreEditorGUI(x);
8 |
9 | )
10 |
11 | // 1 event with 10 seconds duration + 1 event with inf duration
12 |
13 | (
14 | r = UChain(0,0,10,false,[\sine,[\freq,rrand(200.0,500.0)]], \output).fadeOut_(1).fadeIn_(1);
15 | v = UChain(0,1,inf,false,[\sine,[\freq,rrand(200.0,500.0)]], \output).fadeOut_(1).fadeIn_(1);
16 | z = UScore(r,v);
17 | if( z.finiteDuration != 10) { "finiteDuration should be 10".throw };
18 | x = UScoreEditor(z);
19 | y = UScoreEditorGUI(x);
20 |
21 | )
22 |
23 | // 10 event with inf seconds duration
24 | (
25 | r = 10.collect{ |i|
26 | UChain(rrand(0.0,10.0),i,inf,false,[\sine,[\freq,rrand(200.0,500.0)]], \output).fadeOut_(1).fadeIn_(1);
27 | };
28 | z = UScore(*r);
29 | x = UScoreEditor(z);
30 | y = UScoreEditorGUI(x);
31 |
32 | )
33 |
34 | // score within score within a score
35 | //double click scores to enter score
36 | (
37 | f = { 12.collect({ |i|
38 | var evt;
39 | evt = UChain(i/2,i+1,rrand(3.0,10.0),false,\sine, \output).fadeOut_(1).fadeIn_(1);
40 | evt.units[0].set(\freq,rrand(200.0,600.0) );
41 | evt;
42 | }) };
43 | z = UScore(*f.()++[
44 | UScore(*f.()++[
45 | UScore(*f.())
46 | ]
47 | )]);
48 | x = UScoreEditor(z);
49 | y = UScoreEditorGUI(x);
50 |
51 | )
52 |
53 | //some sound files
54 | (
55 | z = UScore(
56 | *12.collect({ |i|
57 | var evt;
58 | evt = BufSndFile("sounds/a11wlk01-44_1.aiff",
59 | rate: (i-6).midiratio, loop: [true,false].wrapAt(i) ).makeUChain
60 | .releaseSelf_(true).startTime_(i/2).track_(i).fadeOut_(1).fadeIn_(1);
61 |
62 | if( evt.duration == inf ) {
63 | evt.duration = 8; // looped events stopped by UScore
64 | };
65 | evt;
66 | })
67 | );
68 | x = UScoreEditor(z);
69 | y = UScoreEditorGUI(x);
70 | )
71 |
72 |
73 | Document.openStartup
--------------------------------------------------------------------------------
/Examples/developer tests/test polygon inside detection.scd:
--------------------------------------------------------------------------------
1 |
2 | //algorithm described here:
3 | //http://blogs.msdn.com/b/devdev/archive/2005/09/01/459540.aspx
4 |
5 |
6 |
7 | (
8 |
9 | n = 3;
10 | p = n.collect{ |i| (0@1).rotate(2pi*i/n) };
11 | ~point = 0.5@0.5;
12 | w = ScaledUserView.window( "WFSSpeakerConf",
13 | Rect( 128, 64, 400, 400 ),
14 | Rect.aboutPoint( 0@0, 2, 2 );
15 | );
16 | w.keepRatio = true;
17 | w.drawFunc = {
18 | var fader, crossfades, lines;
19 | Pen.addArc( ~point.asPoint * (1 @ -1), 0.1/2, 0, 2pi ).fill;
20 |
21 | // draw corns as blue points
22 |
23 | // vector connecting edge k to edge k-1
24 | ~vecs = p.size.collect{ |i| p[i] - p[(i-1).wrap(0,p.size-1)] };
25 | //vector connecting edge k to point
26 | ~vecs2 = p.collect{ |x| ~point - x };
27 | // if crossproducts of vector connecting edge k-1 to k and vector connecting edge k to point
28 | // have all the same sign then it's inside.
29 | if( ~vecs.collect{ |v,i| ((v.x*~vecs2[i].y)-(v.y*~vecs2[i].x)).isPositive }.asSet.size < 2) {
30 | Pen.color = Color.blue;
31 | } {
32 | Pen.color = Color.red;
33 | };
34 | p.do({ |pt|
35 | Pen.addArc( pt.asPoint * (1 @ -1), 0.1/2, 0, 2pi ).fill;
36 | });
37 |
38 |
39 |
40 | };
41 | w.scale = 1;
42 | w.mouseDownAction = { |v, x,y| ~point = (x @ y.neg); };
43 | w.mouseMoveAction = { |v, x,y| ~point = (x @ y.neg); };
44 | )
45 |
46 | // a more weird convex polygon
47 | p = [0@0, 1@0, 1@1, 0.5@1.7, -0.2@1, -0.5@0.5]
--------------------------------------------------------------------------------
/Examples/example scores/live input.uscore:
--------------------------------------------------------------------------------
1 | UScore(
2 | UChain([ 'wfsMasterIn', [ 'numChannels', 8 ] ], [ 'wfsMasterOut', [ 'numChannels', 8 ] ]),
3 | UChain(0.0, 2.0, 'wfsServerIn', [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(0, 8), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
4 | UChain(0.0, 3.0, [ 'wfsServerIn', [ 'bus', 1 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(5.6568542494924, 5.6568542494924), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
5 | UChain(0.0, 4.0, [ 'wfsServerIn', [ 'bus', 2 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(8.0), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
6 | UChain(0.0, 5.0, [ 'wfsServerIn', [ 'bus', 3 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(5.6568542494924, -5.6568542494924), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
7 | UChain(0.0, 6.0, [ 'wfsServerIn', [ 'bus', 4 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(4.8985871965894e-16, -8.0), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
8 | UChain(0.0, 7.0, [ 'wfsServerIn', [ 'bus', 5 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(-5.6568542494924, -5.6568542494924), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
9 | UChain(0.0, 8.0, [ 'wfsServerIn', [ 'bus', 6 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(-8.0, -9.7971743931788e-16), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
10 | UChain(0.0, 9.0, [ 'wfsServerIn', [ 'bus', 7 ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(-5.6568542494924, 5.6568542494924), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
11 | UMarker(0.0, 11.0, "about this score", nil, "This score will route 8 channels of sound input to point sources on the Game Of Life WFS system. The score consists of two parts:
12 |
13 | - one [ wfsMasterIn, wfsMasterOut ] chain:
14 | This chain is only played back on the system's master server. The analog inputs of the master audio interface are routed one by one to the 8 digital inputs of both the system's servers. All this happens in a single (8-channel) chain.
15 |
16 | - 8 [ wfsServerIn, wfsDynamicPoint ] chains:
17 | Each of these chains plays one of the sources. The points are divided in a circle of 8 meter radius across the field, and the first source is at straight front. To edit these positions all at once:
18 | - select all uchains (or none)
19 | - press the light-blue (i) button
20 | - locate the 'point' line under wfsDynamicPoint
21 | - press the [ edit ] button
22 | You can now move each point individually with the mouse, or select multiple and move all at once.
23 |
24 | The duration of all events in the score is infinite, which means it will play indefinitely until you stop the score."),
25 | UMarker(0.0, 13.0, "about OSC control", nil, "This score can also be changed via OSC:
26 | - press the OSC checkbox in the score editor
27 | - note the port number in the message in the post window
28 | - example message setting the point of the first source to 0@2:
29 | [ \"/live input/1/point\", 0, 2 ]")).name_("live input")
30 |
--------------------------------------------------------------------------------
/Examples/example scores/local udef.uscore:
--------------------------------------------------------------------------------
1 | UScore(
2 | UMarker(0.0, 2.0, "about this score", nil, "This score contains a local udef. It is based on the pulse udef, and can be viewed and edited by clicking the [ code ] button in the uchain editor. This udef is saved within the score."),
3 | UChain(0, 0.0, 10.0, LocalUdef('pulse', { |freq = 440, width = 0.5, amp = 0.1, lag = 0|
4 | UMixOut.ar( 0,
5 | Pulse.ar( freq.lag( lag ) + [-1,1],
6 | width.lag( lag ),
7 | amp.lag( lag )
8 | ).sum * 0.5, 0, true )
9 | }, [ ArgSpec('freq', 440, 'freq'.asSpec, false, 'sync'), ArgSpec('width', 0.500000, ControlSpec(0, 1, 'linear', 0, 0.5, ""), false, 'normal'), ArgSpec('amp', 0.100000, 'amp'.asSpec, false, 'normal'), ArgSpec('lag', 0, ControlSpec(0, 1, 'linear', 0.0, 0, ""), false, 'sync'), ArgSpec('u_o_ar_0_bus', 0, ControlSpec(0, 1, 'linear', 1, 0, ""), true, 'sync'), ArgSpec('u_o_ar_0_lvl', 0, 'amp'.asSpec, true, 'sync') ], 'synthesis'), [ 'wfsSource', [ 'point', Point(-0.36227822303772, 8.72687458992), 'maxAmpRadius', 2.0 ] ])).name_("local udef")
10 |
--------------------------------------------------------------------------------
/Examples/example scores/rain/rain.uscore:
--------------------------------------------------------------------------------
1 | UScore(
2 | UChain([ 'rainHF', [ 'seed', 16777216 ] ], [ 'wfsSource', [ 'point', Point(-7, -7), 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]),
3 | UChain(0.0, 1.0, [ 'rainHF', [ 'seed', 12153632 ] ], [ 'wfsSource', [ 'point', Point(-7, 7), 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]),
4 | UChain(0.0, 2.0, [ 'rainHF', [ 'seed', 10895237 ] ], [ 'wfsSource', [ 'point', Point(7, -7), 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]),
5 | UChain(0.0, 3.0, [ 'rainHF', [ 'seed', 80900 ] ], [ 'wfsSource', [ 'point', Point(7, 7), 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]),
6 | UChain(0.0, 4.0, [ 'rainLF', [ 'seed', 53198 ] ], [ 'wfsSource', [ 'point', Point(-7), 'type', 'plane', 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]).displayColor_(Color(0.0, 0.0, 0.76381232071254)),
7 | UChain(0.0, 5.0, [ 'rainLF', [ 'seed', 12334628 ] ], [ 'wfsSource', [ 'point', Point(0, -7), 'type', 'plane', 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]).displayColor_(Color(0.0, 0.0, 0.76381232071254)),
8 | UChain(0.0, 6.0, [ 'rainLF', [ 'seed', 16777216 ] ], [ 'wfsSource', [ 'point', Point(0, 7), 'type', 'plane', 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]).displayColor_(Color(0.0, 0.0, 0.76381232071254)),
9 | UChain(0.0, 7.0, [ 'rainLF', [ 'seed', 10437824 ] ], [ 'wfsSource', [ 'point', Point(7), 'type', 'plane', 'maxAmpRadius', 2.0, 'u_fadeIn', 4.0, 'u_fadeOut', 4.0 ] ]).displayColor_(Color(0.0, 0.0, 0.76381232071254))).name_("rain")
10 |
--------------------------------------------------------------------------------
/Examples/example scores/rain/rainHF.scd:
--------------------------------------------------------------------------------
1 |
2 | Udef(\rainHF, {
3 | URandSeed.ir();
4 | UOut.ar(0,tanh(
5 | 3 * GVerb.ar(
6 | HPF.ar(
7 | PinkNoise.ar(0.08+LFNoise1.kr(0.3,0.02))+LPF.ar(Dust2.ar(LFNoise1.kr(0.2).range(40,50)),7000),
8 | 400
9 | ),
10 | 250,100,0.25,drylevel:0.3
11 | )
12 | ))
13 | })
14 | .category_(\synthesis)
--------------------------------------------------------------------------------
/Examples/example scores/rain/rainLF.scd:
--------------------------------------------------------------------------------
1 | Udef(\rainLF, {
2 | URandSeed.ir();
3 | UOut.ar(0,GVerb.ar(
4 | LPF.ar(
5 | 10 * HPF.ar(PinkNoise.ar(LFNoise1.kr(3).clip(0,1)*LFNoise1.kr(2).clip(0,1) ** 1.8), 20),
6 | LFNoise1.kr(1).exprange(100,2500)
7 | ).tanh,
8 | 270,30,0.7,drylevel:0.5))
9 | })
10 | .category_(\synthesis)
--------------------------------------------------------------------------------
/Examples/example scores/simple automation.uscore:
--------------------------------------------------------------------------------
1 | UScore(
2 | UChain(0, 0, 10.0, [ 'sine', [ 'freq', [ 'envelope', [ 'env', EnvM([ 440.0, 880.0, 440.0 ], [ 5.0, 5.0 ]) ] ] ] ], [ 'wfsSource', [ 'point', Point(-3.5545229911804, 8.11956346035), 'maxAmpRadius', 2.0 ] ]),
3 | UMarker(0.0, 2.0, "automation", { |marker, score|
4 | }, "This example score demonstrates how simple automation can be performed.
5 |
6 | The sine unit in the event in the score uses an UMap for it's frequency. The UMap is of type 'envelope', and holds an envelope that makes the frequency change from 440 to 880 Hz, and back to 440 again in 10 seconds. The envelope can be edited by clicking the 'edit' button in UChain editor.")).name_("simple automation")
7 |
--------------------------------------------------------------------------------
/Examples/example scores/user udef.uscore:
--------------------------------------------------------------------------------
1 | UScore(
2 | UChain(0, 0, 10.0, [ 'sinGrain', [ 'freq', [ 400.0, 1000.0 ] ] ], [ 'wfsSource', [ 'point', [ 'lag_point', [ 'point', Point(1.6357714851181, 7.0028954806266), 'time', 0.5 ] ], 'quality', 'better', 'maxAmpRadius', 2.0 ] ]),
3 | UMarker(0.0, 2.0, "about this score", nil, "This score contains an udef ('sinGrain') that is not in the default system set. The udef file is located in the same folder as the score itself, and therefore will be loaded when the score is opened. You can find the udef in the Udefs window (menu: View -> Udefs, or click the [ udefs ] button in the UChain editor), and from there (on osx systems) you can also open the source code directly.")).name_("user udef")
4 |
--------------------------------------------------------------------------------
/Examples/example scores/user udef/sinGrain.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \sinGrain
3 |
4 | granular synthesis with sine tones.
5 |
6 | This udef belongs to "user udef.uscore" (but can also be used elsewhere). The def will be loaded automatically if it is in the same folder as the score file, or a subfolder of it (as in this case). It will only be loaded if it (or another udef by the same name) is not already in the system.
7 | */
8 |
9 | Udef( \sinGrain, { |freq = #[ 20, 20000 ], dens = 100, overlap = 1, amp = 0.1|
10 | var sig;
11 | URandSeed.ir(); // needed for Udefs with random elements
12 | sig = GrainSin.ar( 1, Dust.ar( dens ), overlap/dens, WhiteNoise.ar.exprange( *freq ) ) * amp;
13 | UOut.ar(0, sig );
14 | })
15 | .category_( \synthesis )
16 | .setSpec( \freq, \freq.asSpec.asRangeSpec.default_( [20,20000] ) )
17 | .setSpec( \dens, [ 1, 1000, \exp, 0, 100 ].asSpec )
18 | .setSpec( \overlap, [ 0.1, 10, \exp, 0, 1 ].asSpec );
19 |
20 |
21 |
--------------------------------------------------------------------------------
/HelpSource/Guides/UChain-GUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/UChain-GUI.png
--------------------------------------------------------------------------------
/HelpSource/Guides/UScoreGUi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/UScoreGUi.png
--------------------------------------------------------------------------------
/HelpSource/Guides/WFSCollider-Code.schelp:
--------------------------------------------------------------------------------
1 | title:: WFSCollider Code interface
2 | summary:: Interfacing with WFSCollider via code.
3 | categories:: WFSCollider
4 | related::Guides/WFSCollider-Overview
5 |
6 | The system can be used just by manipulating the GUIs, but it's also possible to generate scores or chains from code.
7 |
8 | To see examples of how to create WFSCollider objects using SuperCollider code see the reference for link::Classes/UScore:: , link::Classes/UChain:: and link::Classes/U::.
9 |
10 | Below is an example of a reverb using 4 link::Classes/FreeVerb::s patched to 4 plane wave panners. The mix between dry and wet outputs is determined by the distance of the source to the center.
11 |
12 | code::
13 | (
14 | ~points = all {: Point(6*x,6*y), x <- [-1,1], y <- [-1,1]};
15 | UChain(*([\diskSoundFile, \wfsPoint
16 |
17 | ]++4.collect{|i|[
18 | U(\simpleReverb)
19 | .setAudioOut(0,i+1)
20 | .set(\amp,0.8),
21 | U(\wfsStaticPlane)
22 | .setAudioIn(0,i+1)
23 | .point_(~points[i])
24 | ]
25 | }.flat++[\wfsDynamicPoint])).gui
26 | )
27 | ::
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/HelpSource/Guides/WFSCollider-Visual-Guide.schelp:
--------------------------------------------------------------------------------
1 | title:: WFSCollider Visual Guide
2 | summary:: An introduction to graphical user interface of WFSCollider
3 | categories:: WFSCollider
4 |
5 |
6 | SECTION::UChain
7 |
8 | list::
9 | ## To add Units drag from the Udefs window.
10 | ## The mute button silences the output of the UChain. The UChain will still consume cpu cycles.
11 | ::
12 |
13 | image::UChain-GUI.png::
14 |
15 | SECTION::UScore
16 |
17 | The UScore editor consists of a time-line view where events appear as rectangles.
18 |
19 | list::
20 | ## The start position of the score can be changed by double-clicking on an empty area of the score.
21 | ## The events can be dragged to change the start position.
22 | ## Dragging the start and end tips of the event will resize the event.
23 | ## Multiple events can be selected by shift clicking or dragging the mouse in an area without events
24 | ## Events can be duplicated by selecting them and then alt-dragging.
25 | ## Events can be grouped into a sub-score by selecting and hitting the folder icon.
26 | ## Events can be disabled by clicking the speaker icon. Muted events will not be started, so this is a good way to decrease cpu usage.
27 | ## Events can be trimmed or split by first changing the start position of the score and then using the trim/split icons.
28 | ::
29 |
30 | image::UScoreGUI.png::
--------------------------------------------------------------------------------
/HelpSource/Guides/WFSPathGUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/WFSPathGUI.png
--------------------------------------------------------------------------------
/HelpSource/Guides/wfsDynamicIndex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/wfsDynamicIndex.png
--------------------------------------------------------------------------------
/HelpSource/Guides/wfsDynamicPlane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/wfsDynamicPlane.png
--------------------------------------------------------------------------------
/HelpSource/Guides/wfsDynamicPoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/wfsDynamicPoint.png
--------------------------------------------------------------------------------
/HelpSource/Guides/wfsStaticIndex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/wfsStaticIndex.png
--------------------------------------------------------------------------------
/HelpSource/Guides/wfsStaticPlane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/wfsStaticPlane.png
--------------------------------------------------------------------------------
/HelpSource/Guides/wfsStaticPoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Guides/wfsStaticPoint.png
--------------------------------------------------------------------------------
/HelpSource/Tutorials/WFS-Tutorial-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Tutorials/WFS-Tutorial-1.png
--------------------------------------------------------------------------------
/HelpSource/Tutorials/WFS-Tutorial-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GameOfLife/WFSCollider-Class-Library/d9447fb9e2249c58be01b7e43b227286f743ac60/HelpSource/Tutorials/WFS-Tutorial-2.png
--------------------------------------------------------------------------------
/HelpSource/Tutorials/WFSCollider-tutorial.schelp:
--------------------------------------------------------------------------------
1 | title:: A WFSCollider tutorial
2 | summary::Getting started with WFSCollider
3 | categories:: WFSCollider
4 | related::Guides/WFSCollider-Overview
5 |
6 | At it's most simple usage, WFSCollider allows you to assign trajectories to sound files and play them in a time-line. At it's most complex usage it allows arbitrary SuperCollider synths to be spatialized and to be controlled using other synths, osc messages, midi controllers, etc.
7 |
8 | We will start by showing how to play a sound file through a WFS panner.
9 |
10 | To create a new score use menu bar and go to Score->File->new
11 |
12 | To add an event click on the '+' button. By default you get a UChain with two units, sine and output. The output unit is not for WFS playback, so you should change it to one of the WFS Udefs:
13 |
14 | list::
15 | ## wfsDynamicPoint - a point source which can be moved. This is the most common type of source to use.
16 | ## wfsDynamicPlane - a plane wave source which can be moved.
17 | ## wfsDynamicIndex - a source which plays on just one speaker, and the speaker can be changed.
18 | ## wfsStaticPoint - a point source which does not move.
19 | ## wfsStaticPlane - a plane wave source which does not move
20 | ## wfsStaticIndex - a source which plays on just one speaker, the speaker cannot be changed.
21 | ::
22 |
23 | For more info see the link::Guides/WFSCollider-Panners##reference::
24 |
25 | Double-click the event to open it.
26 | Click on "defs" to open the defs window.
27 | Drag the wfsDynamicPoint unit over to the output unit.
28 |
29 | To play the sound file you will need to use one of the sound file players:
30 | list::
31 | ## diskSndFile - play a sound file by streaming it from disk during playback. Allows to play longer files, does not use RAM memory, but if there are too many of these, the disk might not be fast enough to stream all the data.
32 | ## bufSndFile - play a sound file by loading it to memory.
33 | ::
34 |
35 | Drag the diskSndFile unit over to the sine unit.
36 |
37 | To move the sound around there are several possibilities:
38 | list::
39 | ## Move the source using the UChain gui by clicking and dragging the arrow after the "point" argument.
40 | ## Assign a trajectory to the sound using a WFSPathPlayer
41 | ## Use the wfsCirclePath or wfsRandomPath defs for real-time control of the trajectory.
42 | ## Write your own trajectory def. (Look at how wfsCirclePath is written).
43 | ::
44 |
45 | We will use the wfsPathPlayer unit to assign a trajectory to the sound:
46 | Click the '+' button in the diskSndFile unit to add another unit and drag the wfsPathPlayer unit over to that unit.
47 | In the wfsDynamicPoint click on "pointFromBus".
48 |
49 | The UChain GUI should look like:
50 |
51 | image::WFS-Tutorial-1.png::
52 |
53 | To edit the trajectory you can click on "edit" in the wfsPathPlayer section of the UChain gui, this will open a WFSPath editor window.
54 |
55 | image::WFS-Tutorial-2.png::
56 |
57 | You can play the UChain either by clicking the "power" button on the UChain gui or by playing the score using the score editor transport controls.
58 |
59 |
60 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
2 | ===============================================================================
3 |
4 | GameOfLife WFSCollider is a library for SuperCollider, the audio synthesis engine and programming language, for Wave Field Synthesis spatialization.
5 |
6 | It's currently being used in the 192 speakers system of the [Game Of Life Foundation](http://www.gameoflife.nl), based in The Hague, the Netherlands.
7 |
8 | WFSCollider consists of an audio spatialization engine that places individual sound sources in space according to the principles of [Wave Field Synthesis](http://en.wikipedia.org/wiki/Wave_field_synthesis).
9 |
10 | The system allows soundfiles, live input and synthesis processes to be placed in a score editor where start times, and durations can be set and trajectories or positions assigned to each event. It also allows realtime changement of parameters and on the fly starting and stopping of events via GUI or OSC control. Each event can be composed of varous objects ("units") in a processing chain.
11 |
12 | Score files are saved as executable SuperCollider code. The system is setup in a modular way and can be scripted and expanded using the SuperCollider language.
13 |
14 | WFSCollider is distributed as a 'Quark' for SuperCollider. For installation instructions see: [www.gameoflife.nl/software](http://www.gameoflife.nl/software).
15 |
16 |
17 | ## System Requirements ##
18 |
19 | macOS 10.14 or later, Linux or Windows 64bits
20 |
21 | Depends on:
22 |
23 | * [SuperCollider 3.13](https://supercollider.github.io/)
24 | * the Unit-Lib, NetLib, wslib and XML quarks.
25 | * [sc3plugins](https://supercollider.github.io/sc3-plugins/) (optional)
26 |
27 | ## Installation ##
28 |
29 | - Install SuperCollider
30 | - Install sc3plugins (optional)
31 | - in SuperCollider, run the following line:
32 | `Quarks.install( "WFSCollider-Class-Library" );`
33 | - Recompile Class Library (via menu option in SuperCollider)
34 | - to use WFSCollider, run the following line in SuperCollider
35 | `WFSLib.startup;`
36 |
37 | ## Acknowledgments ##
38 | WFSCollider was conceived by the Game Of Life Foundation, and developed by W. Snoei, R. Ganchrow and J. Truetzler and M. Negrão.
39 |
40 | ## License ##
41 | Both SuperCollider and the WFSCollider library are licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
42 |
43 |
--------------------------------------------------------------------------------
/V1-Compatibility/WFS Classes/Engine/wfsSynthPlus.sc:
--------------------------------------------------------------------------------
1 | /*
2 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
3 | The Game Of Life Foundation. http://gameoflife.nl
4 | Copyright 2006-2010 Wouter Snoei.
5 |
6 | GameOfLife WFSCollider software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | GameOfLife WFSCollider is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with GameOfLife WFSCollider. If not, see .
18 | */
19 |
20 | + String { // from defname ( "WFS_intType_audioType" )
21 | wfsIntType { ^this.split( $_ )[1].asSymbol; }
22 | wfsAudioType { ^this.split( $_ )[2].asSymbol; }
23 |
24 | wfsIntType_ { |type| var out; // not in place: returns new string!!
25 | out = this.split( $_ )[1] = type;
26 | ^out.join( $_ );
27 | }
28 |
29 | wfsAudioType_ { |type| var out;
30 | out = this.split( $_ )[2] = type;
31 | ^out.join( $_ );
32 | }
33 |
34 | asWFSSynthDefType { ^(this.wfsIntType ++ "_" ++ this.wfsAudioType).asSymbol }
35 | }
36 |
37 | + Symbol {
38 | wfsIntType { ^this.asString.wfsIntType; }
39 | wfsAudioType { ^this.asString.wfsAudioType; }
40 | asWFSSynthDefType { ^this.asString.asWFSSynthDefType; }
41 | }
--------------------------------------------------------------------------------
/V1-Compatibility/WFS Classes/Spatial Objects/asWFSPoint.sc:
--------------------------------------------------------------------------------
1 | /*
2 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
3 | The Game Of Life Foundation. http://gameoflife.nl
4 | Copyright 2006-2010 Wouter Snoei.
5 |
6 | GameOfLife WFSCollider software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | GameOfLife WFSCollider is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with GameOfLife WFSCollider. If not, see .
18 | */
19 |
20 | + Object {
21 | isWFSPoint { ^false }
22 | asWFSPoint { ^nil }
23 | asWFSSpeaker { ^nil }
24 | isWFSSpeaker { ^false }
25 | isWFSPath { ^false }
26 | asWFSPath { ^nil }
27 | couldBeWFSPoint { ^false }
28 |
29 | }
30 |
31 | + Collection {
32 | asWFSPoint { ^WFSPoint(*this) }
33 | asWFSSpeaker { ^WFSSpeaker(*this) }
34 | asWFSPath { ^WFSPath_Old( this.collect( _.asWFSPoint ) ) }
35 | asWFSPointArray { ^WFSPointArray.with( *this ) }
36 | asWFSPathArray { ^WFSPathArray.with(*this) }
37 | asWFSSpeakerArray { ^WFSSpeakerArray.with(*this) }
38 | asWFSSpeakerLine { ^WFSSpeakerLine.with(*this) }
39 |
40 | couldBeWFSPoint { ^(this.size < 4) && { this.every( { |item|
41 | item.size == 0 } ) };
42 | }
43 |
44 |
45 | writeWFSFile { |path = "~/scwork/wfsPathsOut.xml", name="example"|
46 | var array;
47 | array = this.asWFSPathArray;
48 | if( array.isValid )
49 | { ^array.writeWFSFile(path, name) }
50 | { "this is not an Array containing WFSPaths".error };
51 | }
52 |
53 | writeSVGFile { |path = "~/scwork/wfsPathsOut.svg", name="example"|
54 | var array;
55 | array = this.asWFSPathArray;
56 | if( array.isValid )
57 | { ^array.writeSVGFile(path, name) }
58 | { "this is not an Array containing WFSPaths".error };
59 | }
60 | }
61 | + String {
62 | asWFSPoint { ^nil }
63 | asWFSSpeaker {^nil }
64 | asWFSPath { ^nil }
65 | }
66 |
67 | + Number {
68 | asWFSPoint { |amount = 3| // fill in the number at all slots or only 1 or 2
69 | ^WFSPoint(*this.dup(amount)) }
70 |
71 | asWFSSpeaker { |angle = 0| ^this.asWFSPoint.asWFSSpeaker(angle) }
72 |
73 | couldBeWFSPoint { ^true }
74 | }
75 |
76 | + Point {
77 | asWFSPoint { |z = 0| ^WFSPoint(x,y,z); }
78 | asWFSSpeaker { |z=0, angle=0| ^WFSSpeaker(x,y,z,angle) }
79 |
80 | couldBeWFSPoint { ^true }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/V1-Compatibility/WFS Classes/WFSTools.sc:
--------------------------------------------------------------------------------
1 | /*
2 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
3 | The Game Of Life Foundation. http://gameoflife.nl
4 | Copyright 2006-2010 Wouter Snoei.
5 |
6 | GameOfLife WFSCollider software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | GameOfLife WFSCollider is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with GameOfLife WFSCollider. If not, see .
18 | */
19 |
20 | WFSTools {
21 |
22 | *makeWFSPointsArray { arg inArray; // for WFSPath
23 | if(inArray.size < 2)
24 | { "A WFSPath should contain at least 2 positions".warn; };
25 | ^inArray.collect({ |item| item.asWFSPoint });
26 | }
27 |
28 | *asRadians { |in| ^(in / WFSPath_Old.azMax) * 2pi; }
29 |
30 | *fromRadians { |in| ^(in / 2pi) * WFSPath_Old.azMax; }
31 |
32 | *singleAZToXY { arg az, d, center = 0, azMax; // with contol/audio rate support
33 | var x, y;
34 |
35 | azMax = azMax ? WFSPath_Old.azMax;
36 | if(azMax != 2pi, {az = (az / azMax) * 2pi});
37 |
38 | case { az.rate == 'control' }
39 | { ^([SinOsc.kr(0, az), SinOsc.kr(0, az - (0.5pi))] * d ) + center; }
40 | { az.rate == 'audio' }
41 | { ^([SinOsc.ar(0, az), SinOsc.ar(0, az - (0.5pi))] * d ) + center; }
42 | { true }
43 | { ^([az.sin, az.cos] * d) + center; };
44 |
45 | }
46 |
47 | *azToXY { arg inArray, center = 0, round = 1.0e-16, azMax; //2D
48 | azMax = azMax ? WFSPath_Old.azMax;
49 | ^inArray.collect({ |item|
50 | var azimuth, distance;
51 | # azimuth, distance = item;
52 | if(azMax != 2pi, {azimuth = (azimuth / azMax) * 2pi});
53 | ([azimuth.sin.round(round), azimuth.cos.round(round)] * distance) + center; });
54 | }
55 |
56 | *xyToAZ { arg inArray, center = 0, azMax; //2D
57 | azMax = azMax ? WFSPath_Old.azMax;
58 | if(center.class == WFSPoint)
59 | { center = [center.x, center.y]; };
60 | ^inArray.collect({ |item|
61 | var azimuth, distance, xx, yy;
62 | #xx, yy = item - center;
63 | azimuth = atan2(xx,yy) % 2pi; //theta
64 | distance = hypot(xx,yy); //rho
65 | if(azMax != 2pi, {azimuth = (azimuth / 2pi) * azMax});
66 | [azimuth, distance];
67 | })
68 | }
69 |
70 | *validateTimeLine { |timeLine|
71 | var lastTime = 0;
72 | ^timeLine.collect({ |item|
73 | var out;
74 | if(item < lastTime)
75 | { out = item + lastTime; "validateTimeLine: corrected 1 timeLine item".postln; }
76 | { out = item;};
77 | lastTime = out;
78 | out; });
79 | }
80 |
81 | }
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/brown.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \brown, { |f, n = 1|
2 | var range, center, step, stream;
3 | range = f.get( \range );
4 | thisThread.randSeed = f.get( \seed );
5 | step = f.get( \step ) * (range[1] - range[0]);
6 | center = f.get( \center ).linlin(0,1,*range);
7 | stream = Pcbrown( range[0], range[1], step, center ).asStream;
8 | stream.nextN( n );
9 | }, [ \range, [0.0,1.0], \step, 0.125, \center, 0.5, \seed, 12345 ], { |f, obj|
10 | [
11 | \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
12 | \step, f.get( \step ),
13 | \center, f.get( \center ),
14 | \seed, 1569325056.rand ]
15 | } )
16 | .mappedArgs_([ \range ])
17 | .setSpec( \range, [0,1].asSpec.asRangeSpec )
18 | .setSpec( \center, [0,1,\lin,0,0.5].asSpec )
19 | .setSpec( \step, [0,1].asSpec )
20 | .setSpec( \seed, PositiveIntegerSpec(12345) );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/line.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \line, { |f, n = 1|
2 | var a, b, curve;
3 | if( f.get( \direction ) == \down ) {
4 | #b, a = f.get( \range );
5 | } {
6 | #a, b = f.get( \range );
7 | };
8 | curve = f.get( \curve );
9 | n.collect({ |i|
10 | i.lincurve( 0, n-1, a, b, curve );
11 | });
12 |
13 | }, [ \range, [0,1], \direction, \up, \curve, 0 ], { |f, obj|
14 | [ \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
15 | \direction, f.get( \direction ), \curve, f.get( \curve ) ]
16 | } )
17 | .mappedArgs_([ \range ])
18 | .setSpec( \range, [0,1].asSpec.asRangeSpec )
19 | .setSpec( \direction, ListSpec( [\up, \down] ) )
20 | .setSpec( \curve, [ -16, 16, \lin, 0, 0 ].asSpec );
21 |
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/linrand.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \linrand, { |f, n = 1|
2 | var range;
3 | range = f.get( \range );
4 | thisThread.randSeed = f.get( \seed );
5 | n.collect({ |i|
6 | 1.0.linrand.linlin(0,1,*range);
7 | });
8 |
9 | }, [ \range, [0.0,1.0], \seed, 12345 ], { |f, obj|
10 | [ \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
11 | \seed, 1569325056.rand ]
12 | } )
13 | .mappedArgs_([ \range ])
14 | .setSpec( \range, [0,1].asSpec.asRangeSpec )
15 | .setSpec( \seed, PositiveIntegerSpec(12345) );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/pulse.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \pulse, { |f, n = 1|
2 | var phase, width, periods, range, close, size;
3 | periods = f.get( \periods );
4 | width = f.get( \width );
5 | phase = f.get( \phase ) / 2;
6 | range = f.get( \range );
7 | close = f.get( \close ).not.binaryValue;
8 | n.collect({ |i|
9 | ((((i * periods) / (n-close)) + phase).wrap(0,1) < width )
10 | .binaryValue
11 | .linlin(0,1,*range);
12 | });
13 |
14 | }, [ \range, [0.0,1.0], \periods, 1, \width, 0.5, \phase, 0, \close, true ], { |f, obj|
15 | [
16 | \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
17 | \periods, f.get( \periods ),
18 | \width, f.get( \width ),
19 | \phase, f.get( \phase ),
20 | \close, f.get( \close )
21 | ]
22 | } )
23 | .mappedArgs_([ \range ])
24 | .setSpec( \periods, [0, inf, \lin, 0.125].asSpec )
25 | .setSpec( \width, [0, 1, \lin, 0, 0.5].asSpec )
26 | .setSpec( \phase, [0,2,\lin].asSpec )
27 | .setSpec( \range, [0,1].asSpec.asRangeSpec );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/random.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \random, { |f, n = 1|
2 | var range;
3 | range = f.get( \range );
4 | thisThread.randSeed = f.get( \seed );
5 | n.collect({ |i|
6 | range[0] rrand: range[1]
7 | });
8 |
9 | }, [ \range, [0.0,1.0], \seed, 12345 ], { |f, obj|
10 | [ \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
11 | \seed, 1569325056.rand ]
12 | } )
13 | .mappedArgs_([ \range ])
14 | .setSpec( \range, [0,1].asSpec.asRangeSpec )
15 | .setSpec( \seed, PositiveIntegerSpec(12345) );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/sine.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \sine, { |f, n = 1|
2 | var phase, periods, range, close;
3 | periods = f.get( \periods );
4 | phase = f.get( \phase ) * pi;
5 | range = f.get( \range );
6 | close = f.get( \close ).not.binaryValue;
7 | n.collect({ |i|
8 | (i.linlin(0,n-close,0,2pi * periods) + phase).sin.linlin(-1,1,*range);
9 | });
10 |
11 | }, [ \range, [0.0,1.0], \periods, 1, \phase, 0, \close, true ], { |f, obj|
12 | [ \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
13 | \periods, f.get( \periods ), \phase, f.get( \phase ), \close, f.get( \close ) ]
14 | } )
15 | .mappedArgs_([ \range ])
16 | .setSpec( \periods, [0, inf, \lin, 0.125].asSpec )
17 | .setSpec( \phase, [0,2,\lin].asSpec )
18 | .setSpec( \range, [0,1].asSpec.asRangeSpec );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/spline.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \spline, { |f, n = 1|
2 | var range, p1, direction;
3 | range = f.get( \range );
4 | p1 = range.splineIntPart1( f.get( \c1 ), f.get( \c2 ) );
5 | direction = (up: 1, down: 0)[ f.get( \direction ) ];
6 | n.collect({ |i|
7 | p1.splineIntPart2( i.linlin( 0, n-1, 1-direction, direction).abs );
8 | });
9 |
10 | }, [ \range, [0,1], \direction, \up, \c1, 1/3, \c2, 2/3 ], { |f, obj|
11 | [ \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
12 | \direction, f.get( \direction ), \c1, f.get( \c1 ), \c2, f.get( \c2 )
13 | ]
14 | } )
15 | .mappedArgs_([ \range ])
16 | .setSpec( \range, [0,1].asSpec.asRangeSpec )
17 | .setSpec( \direction, ListSpec( [\up, \down] ) )
18 | .setSpec( \c1, [0,1,\lin,0,1/3].asSpec )
19 | .setSpec( \c2, [0,1,\lin,0, 2/3].asSpec );
20 |
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayGeneratorDefs/tri.scd:
--------------------------------------------------------------------------------
1 | ArrayGeneratorDef( \tri, { |f, n = 1|
2 | var phase, periods, range, close;
3 | periods = f.get( \periods ) * 2;
4 | phase = f.get( \phase ) * 2;
5 | range = f.get( \range );
6 | close = f.get( \close ).not.binaryValue;
7 | n.collect({ |i|
8 | (i.linlin(0,n-close,0,2 * periods) + phase).fold(-1,1).linlin(-1,1,*range);
9 | });
10 |
11 | }, [ \range, [0.0,1.0], \periods, 1, \phase, 0, \close, true ], { |f, obj|
12 | [ \range, if( obj.minItem == obj.maxItem ) { [0,1] } { [ obj.minItem, obj.maxItem ] },
13 | \periods, f.get( \periods ), \phase, f.get( \phase ), \close, f.get( \close ) ]
14 | } )
15 | .mappedArgs_([ \range ])
16 | .setSpec( \periods, [0, inf, \lin, 0.125].asSpec )
17 | .setSpec( \phase, [0,2,\lin].asSpec )
18 | .setSpec( \range, [0,1].asSpec.asRangeSpec );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/clip.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \clip, { |f, obj|
2 | var range;
3 | range = f.get( \clip );
4 | if( (range[1] - range[0]) > 0 ) {
5 | obj = obj.linlin( *range ++ [-1,1,'none'] );
6 | switch( f.get( \clipMode ),
7 | \clip, { obj.softclip2(1, f.get( \clipSoftness ) ); },
8 | \sineClip, { obj.sineclip2(1, f.get( \clipSoftness ) ); },
9 | \fold, { obj.softfold2(1, f.get( \clipSoftness ) ); },
10 | \wrap, { obj.softwrap2(1, f.get( \clipSoftness ) ); },
11 | \excess, { obj.softexcess2(1, f.get( \clipSoftness ) ); },
12 | { obj }
13 | ).linlin( *[-1,1] ++ range ++ [ 'none' ] );
14 | } {
15 | switch( f.get( \clipMode ),
16 | \clip, { obj.clip(*range); },
17 | \sineClip, { obj.clip(*range); },
18 | \fold, { obj.fold(*range); },
19 | \wrap, { obj.wrap(*range); },
20 | \excess, { obj },
21 | { obj }
22 | );
23 | };
24 | }, [ \clip, #[0,1], \clipMode, \clip, \clipSoftness, 0.0 ], { |f, obj|
25 | [ \clip, #[0,1], \clipMode, f.get( \clipMode ), \clipSoftness, 0.0 ]
26 | } )
27 | .bypassFunc_({ |f, obj| f.get( \clipMode ) == \off })
28 | .mappedArgs_([\clip])
29 | .setSpec( \clip, [0,1].asSpec.asRangeSpec )
30 | .setSpec( \clipMode, ListSpec( [ \clip, \sineClip, \fold, \wrap, \excess, \off ] ) )
31 | .setSpec( \clipSoftness,[0,1].asSpec );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/curve.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \curve, { |f, obj|
2 | var curve, range;
3 | curve = f.get( \curve );
4 | range = [ obj.minItem, obj.maxItem ];
5 | if( (abs(curve) >= 0.001) && { (range[1] - range[0]) > 0 } ) {
6 | obj.lincurve( *range ++ range ++ [ curve, 'none' ] );
7 | } {
8 | obj;
9 | };
10 | }, [ \curve, 0 ] )
11 | .setSpec( \curve, [-16,16,\lin,0,0].asSpec );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/offset.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \offset, { |f, obj|
2 | obj + f.get( \offset );
3 | }, [ \offset, 0 ] ).setSpec( \offset, [-1,1,\lin,0,0].asSpec );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/rotate.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \rotate, { |f, obj|
2 | obj = obj.permute( f.get( \permute ).asInteger );
3 | obj = obj.rotate( f.get( \rotate ).asInteger );
4 | if( f.get( \reverse ) == true ) {
5 | obj.reverse;
6 | } {
7 | obj;
8 | };
9 | }, [ \permute, 0, \rotate, 0, \reverse, false ] )
10 | .setSpec( \permute, [0,inf,\lin,1,0].asSpec )
11 | .setSpec( \rotate, [-inf,inf,\lin,1,0].asSpec )
12 | .setSpec( \reverse, BoolSpec(false) )
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/round.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \round, { |f, obj|
2 | if( f.spec.notNil ) {
3 | f.spec.unmap( f.spec.map( obj ).round( f.getMapped( \round ) ) );
4 | } {
5 | obj.round( f.get( \round ) );
6 | };
7 | }, [ \round, 0.0] )
8 | .mappedArgs_( [ \round ] )
9 | .setSpec( \round, UAdaptSpec({ |spec|
10 | var x;
11 | if( spec.notNil ) {
12 | spec = ControlSpec.newFrom( spec );
13 | if( spec.warp.isKindOf( ExponentialWarp ) ) {
14 | x = (spec.map(0.5)
15 | .linlin( spec.minval, spec.maxval, 0, 1 ).reciprocal-1).squared.log;
16 | };
17 | spec.minval = 0;
18 | spec.default = 0;
19 | if( x.notNil ) { spec.warp = x; };
20 | spec;
21 | } {
22 | ControlSpec( 0, 1, \lin, 0.0, 0 );
23 | };
24 | })
25 | );
26 |
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/scale.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \scale, { |f, obj|
2 | var center;
3 | center = [ obj.maxItem, obj.minItem ].mean;
4 | ((obj - center) * f.get( \scale ) * (if( f.get( \invert ) ) { -1 } { 1 })) + center;
5 | }, [ \scale, 1, \invert, false] )
6 | .setSpec( \scale, [0,8,7.squared.log,0,1].asSpec )
7 | .setSpec( \invert, BoolSpec( false ) );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/smooth.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \smooth,
2 | { |f, obj|
3 | var newPos, win, n, amt, mode;
4 | n = (f.get( \window ) * obj.size).max(3).round(2);
5 | amt = f.get( \smooth );
6 | mode = (f.get( \mode ).asString ++ "At").asSymbol;
7 | win = ({ |i|
8 | i.linlin(0,(n-1).max(2),-0.5pi,1.5pi).sin.linlin(-1,1,0,1)
9 | }!n.max(2)).normalizeSum;
10 | obj.blend( obj.collect({ |item, i|
11 | var out, sum;
12 | out = obj.perform( mode, (i + (n/ -2).ceil .. i + (n/2).ceil - 1) ) * win;
13 | sum = 0;
14 | out.do({ |item| sum = sum + item; });
15 | sum;
16 | }), amt );
17 | },
18 | [ \smooth, 0, \window, 0.3, \mode, \clip ],
19 | { |f, path| [ \smooth, 0, \window, f.get( \window ), \mode, f.get( \mode ) ] }
20 | )
21 | .setSpec( \smooth, ControlSpec( -1, 1, \lin, 0, 0 ) )
22 | .setSpec( \window, ControlSpec( 0, 1, \lin, 0.0, 0.3 ) )
23 | .setSpec( \mode, ListSpec( [ \clip, \wrap, \fold ] ) )
24 | .useSelection_( false );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/sort.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \sort,
2 | { |f, obj|
3 | var sorted, old, type;
4 | type = f.get( \sort );
5 | if( type != \scramble ) { f.environment[ \seed ] = nil; };
6 | switch( type,
7 | \up, {
8 | obj.sort({ |a,b|
9 | a.rho <= b.rho;
10 | });
11 | },
12 | \down, {
13 | obj.sort({ |a,b|
14 | a.rho >= b.rho;
15 | });
16 | },
17 | \scramble, {
18 | if( f.environment[ \seed ].isNil ) {
19 | f.environment[ \seed ] = 1569325056.rand;
20 | };
21 | thisThread.randSeed = f.environment[ \seed ];
22 | obj.scramble;
23 | },
24 | \nearest, {
25 | old = obj.deepCopy.reverse;
26 | sorted = Array( old.size );
27 | sorted.add( old.pop );
28 | old.size.do({
29 | old.sort({ |a,b|
30 | a.absdif( sorted.last ) >= b.absdif( sorted.last )
31 | });
32 | sorted.add( old.pop );
33 | });
34 | sorted;
35 | },
36 | { obj }
37 | );
38 | },
39 | [ \sort, \off ]
40 | )
41 | .setSpec( \sort, ListSpec( [ \off, \up, \down, \scramble, \nearest ] ) );
--------------------------------------------------------------------------------
/WFS/ArrayTransformer/ArrayTransformerDefs/tilt.scd:
--------------------------------------------------------------------------------
1 | ArrayTransformerDef( \tilt, { |f, obj|
2 | var tiltAmt, size;
3 | tiltAmt = ((f.get( \tilt ) * 0.5pi).tan / 2);
4 | size = obj.size;
5 | obj.collect({ |item, i|
6 | item + i.linlin(0,size-1,tiltAmt.neg, tiltAmt)
7 | });
8 | }, [ \tilt, 0] )
9 | .setSpec( \tilt, [-1,1,\lin,0,0].asSpec );
--------------------------------------------------------------------------------
/WFS/UMapDefs/circle_trajectory.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \circle_trajectory
3 |
4 | Creates an UMap for generating a circular or elliptical trajectory for modulatable point parameters.
5 |
6 | speed: frequency (cycles per second).
7 | startAngle: starting angle of the path in degrees.
8 | clockwise: select to turn clockwise, otherwise the path turns anti-clockwise.
9 | center: the center of the circle (Point).
10 | radius: x and y radius of the circle/ellipse (Point).
11 |
12 | --
13 | this is an UMapDef definition file
14 | part of the WFSCollider Class Library default UMapDefs set
15 | */
16 |
17 | UMapDef( \circle_trajectory, { |
18 | speed = 0.1,
19 | startAngle = 0,
20 | clockwise = 1,
21 | center = #[0.0,0.0],
22 | radius = #[10.0,10.0],
23 | u_startPos = 0|
24 | var circle;
25 | u_startPos = (u_startPos * DC.kr( speed ) * 2pi).wrap(0,2pi);
26 | circle = SinOsc.kr(
27 | speed * clockwise.linlin(0,1,-1,1),
28 | [ 0, 0.5pi ] + startAngle + u_startPos,
29 | radius,
30 | center
31 | );
32 | UMapOut.kr( circle, false );
33 | })
34 | .category_( 'point_trajectory' )
35 | .canInsert_( false )
36 | .canUseUMapFunc_({ |unit, key, umapdef|
37 | unit.getSpec( key ).isKindOf( PointSpec );
38 | })
39 | .setSpec( \speed, [ 0, 100, 1.calcCurve(0,100), 0, 0.1 ].asSpec )
40 | .setSpec( \startAngle, AngleSpec() )
41 | .setSpec( \clockwise, BoolSpec( true ) )
42 | .setSpec( \center, WFSPointSpec(200) )
43 | .setSpec( \radius, WFSRadiusSpec(200) )
44 | .setSpec( \lag, [ 0, 1, \lin, 0, 0].asSpec );
--------------------------------------------------------------------------------
/WFS/UMapDefs/clip_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \clip_point
3 |
4 | Creates an UMap for applying clipping, wrapping, folding (mirroring) and more on points
5 |
6 | point: the point to clip
7 | center: the center of the clipping area
8 | radius: the radius of the clipping area
9 | clipMode: can be one of the following modes:
10 | 0 - 'clip' (default): clip coordinates outside clipping area
11 | 1 - 'fold': fold/mirror coordinates outside clipping area
12 | 2 - 'wrap': wrap around coordinates outside clipping area
13 | 3 - 'none': no clipping applied (values can go outside clipping area)
14 | clipSoftness: softens the edges of 'clip' and 'fold' modes (0-1).
15 |
16 | The value arg range is mapped to that of the parameter to which the UMap is connected.
17 |
18 | --
19 | this is an UMapDef definition file
20 | part of the WFSCollider Class Library default UMapDefs set
21 | */
22 |
23 |
24 | UMapDef( \clip_point, { |
25 | point = #[0.0, 0.0],
26 | center = #[0.0, 0.0],
27 | radius = #[10.0, 10.0],
28 | clipMode = 0,
29 | clipSoftness = 0.1|
30 | radius = radius.max(1.0e-10);
31 | point = point - center;
32 | point = point.linlin( radius.neg, radius, -1, 1, \none );
33 | point = Select.kr( clipMode, [
34 | point.softclip2(1, clipSoftness ),
35 | point.softfold2(1, clipSoftness ),
36 | point.wrap2(1),
37 | point
38 | ]);
39 | point = point.linlin( -1, 1, radius.neg, radius, \none ) + center;
40 | UMapOut.kr(point, false);
41 | })
42 | .setSpec( \point, WFSPointSpec(200) )
43 | .setSpec( \center, WFSPointSpec(200) )
44 | .setSpec( \radius, WFSRadiusSpec(Rect(0,0,200,200)) )
45 | .setSpec( \clipMode, ListSpec( (..3), 0, [ \clip, \fold, \wrap, \none ] ) )
46 | .setSpec( \clipSoftness, [0,1,\lin,0,0.1].asSpec )
47 | .category_( 'point_utility' )
48 | .canUseUMapFunc_({ |unit, key, umapdef|
49 | unit.getSpec( key ).isKindOf( PointSpec );
50 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/crossfade_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \crossfade_point
3 |
4 | Creates an UMap for crossfading between two points via linear interpolation. The points can also be UMaps.
5 |
6 | a: the first point
7 | b: the second point
8 | crossfade: (0-1) the crossfading position (a to b)
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \crossfade_point, { |
16 | a = #[0.0, 0.0],
17 | b = #[10.0,10.0],
18 | crossfade = 0.5|
19 | UMapOut.kr( (a * (1-crossfade)) + (b * crossfade), false );
20 | })
21 | .category_( 'point_utility' )
22 | .canUseUMapFunc_({ |unit, key, umapdef|
23 | unit.getSpec( key ).isKindOf( PointSpec );
24 | })
25 | .setSpec( \a, WFSPointSpec(200) )
26 | .setSpec( \b, WFSPointSpec(200) );
--------------------------------------------------------------------------------
/WFS/UMapDefs/delay_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \delay_point
3 |
4 | Creates an UMap for applying a delay to a point input. When the point is moving the delayed point will always follow behind it.
5 |
6 | point: the point to lag
7 | time: the length of the delay.
8 | timeScale: the number of seconds by which 'time' is multiplied. This value can not be changed during playback.
9 | lag: smoothing time applied to change of delay time, use to prevent sudden jumps during change of delay time.
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 |
17 | UMapDef( \delay_point, { |
18 | point = #[0.0, 0.0],
19 | time = 0.1,
20 | timeScale = 1,
21 | lag = 0
22 | |
23 | var delayed;
24 | time = time.lag3( lag ) * timeScale;
25 | delayed = DelayC.kr( point, timeScale * 2, time );
26 | point = Select.kr( Line.kr(0,1,time) >= 1, [Latch.kr( point, Impulse.kr(0) ), delayed] );
27 | UMapOut.kr(point, false);
28 | })
29 | .setSpec( \point, WFSPointSpec(200, 0.1) )
30 | .setSpec( \time, [ 0, 2, \lin, 0, 0.1 ] )
31 | .setSpec( \timeScale, ListSpec([0.1,1,10],1,["0.1s", "1s", "10s"]), \init )
32 | .setSpec( \lag, [0,1,\lin].asSpec )
33 | .category_( 'point_filter' )
34 | .canUseUMapFunc_({ |unit, key, umapdef|
35 | unit.getSpec( key ).isKindOf( PointSpec );
36 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/envir_point_get.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \envir_point_get
3 |
4 | Creates an pattern UMap for getting environment variables. Use in conjunction with the 'envir_value' Udef. Environment values are also accessible via regular SuperCollider code, by adding a '~' in front of the name.
5 |
6 | key: the name of the variable (default: 'a')
7 |
8 | The value will automatically be scaled to the value range of the parameter to which the UMap is connected.
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the Unit lib default UMapDefs set
13 | */
14 |
15 | ValueUMapDef( \envir_point_get, { |unit, ctrl|
16 | var kkey, val, spec, fromSpec;
17 | ctrl.remove;
18 | kkey = unit.get( \key );
19 | spec = unit.getSpec( \value );
20 | ctrl = SimpleController( currentEnvironment )
21 | .put( kkey, {
22 | val = currentEnvironment[ kkey ] ? (spec.default);
23 | fromSpec = currentEnvironment[ \u_specs ] !? _[ kkey ] ? spec;
24 | if( val.isCollection ) {
25 | val = val.wrapAt( unit.get( \index ).asInteger );
26 | };
27 | if( val.isKindOf( Point ).not ) {
28 | val = spec.constrain( val.asPoint );
29 | };
30 | unit.set( \value, val );
31 | });
32 | currentEnvironment.changed( kkey );
33 | ctrl
34 | }, { |unit, ctrl|
35 | ctrl.remove;
36 | nil;
37 | },[
38 | [ \key, \p, EnvirSpec() ],
39 | [ \index, 0, IntegerSpec(0,0,1024) ],
40 | ], \control )
41 | .numChannels_( 2 )
42 | .setSpec( \value, WFSPointSpec(200) )
43 | .canUseUMapFunc_({ |unit, key, umapdef|
44 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
45 | unit.getSpec( key ).isMemberOf( class )
46 | });
47 | })
48 | .category_( 'envir' );
--------------------------------------------------------------------------------
/WFS/UMapDefs/follow_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \follow_point
3 |
4 | Creates an UMap for applying speed and rotation limits to a point input.
5 |
6 | point: the point to follow
7 | maxSpeed: maximum speed in m/s
8 | maxRotation: maximum rotation in deg/s
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \follow_point, { |
16 | point = #[0.0, 0.0],
17 | maxSpeed = 1,
18 | maxRotation = 180
19 | |
20 | var fp, initPoint, delta, angle, x, y;
21 | maxSpeed = maxSpeed * ControlDur.ir;
22 | maxRotation = maxRotation * (1/180pi);
23 | initPoint = DC.kr( point );
24 | #x,y,angle = LocalIn.ar(3);
25 | fp = initPoint + [x,y];
26 | delta = (point - fp).asPoint.asPolar;
27 | delta.rho = delta.rho.min( maxSpeed );
28 | delta.theta = if( delta.rho < maxSpeed,
29 | delta.theta,
30 | (delta.theta - angle).wrap2( pi ).clip2( maxRotation ) + angle
31 | );
32 | angle = if( delta.rho > 0, delta.theta, angle );
33 | delta = delta.asPoint.asArray;
34 | fp = fp + delta;
35 | LocalOut.ar( (fp - initPoint) ++ [ angle ] );
36 | UMapOut.kr(fp, false);
37 | })
38 | .setSpec( \point, WFSPointSpec(200, 0.1) )
39 | .setSpec( \maxSpeed, [0,344,8].asSpec )
40 | .setSpec( \maxRotation, [0,180,\lin].asSpec )
41 | .category_( 'point_filter' )
42 | .canUseUMapFunc_({ |unit, key, umapdef|
43 | unit.getSpec( key ).isKindOf( PointSpec );
44 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/index_trajectory.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \index_trajectory
3 |
4 | Creates an UMap for indexing through 2D spatial trajectories. Via the 'index' value, which can be another UMap, all positions on the course of the path can be reached. The index scales between 0 and 1, the start and end positions of the trajectory. The time information stored in the trajectory object is not used; the distance between the breakpoints is used equally. This umap is intended for use on units with PointSpec or WFSPointSpec based args.
5 |
6 | index: a value between 0 and 1, referring to the start and end points of the path. If the path is set to 'loop', the path is extended by adding the start point as last point.
7 | trajectory: a WFSPathBuffer object. This object creates and points to a buffer with the data of the trajectory. This buffer is either filled with data sent directly, or data read from a .wfspath file (generated via the [write data] button in the GUI). Data from file is usually more reliable than sending via network. Note that the 'delay' and 'rate' settings have no effect on the behaviour of this UMap.
8 | addPoint: a point (or point UMap) can be added to the trajectory position, effectively moving the trajectory as a whole.
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \index_trajectory, {
16 | var sig, index, bufFrames, numDim = 2;
17 | var bufnum, startFrame, rate, loop, delay;
18 | index = \index.kr(0.0);
19 | #bufnum, startFrame, rate, loop, delay = WFSPathBufferPlayer.getArgs( \trajectory );
20 | bufFrames = BufFrames.kr( bufnum ) - 1;
21 | index = (index * (bufFrames + loop));
22 | sig = BufRd.kr( (numDim * 4) + 1, bufnum, index, 1, 1 );
23 | sig = numDim.collect({ |i| sig[ (1..4) + (i*4) ].splineIntPart2( index.wrap(0,1) ); });
24 | sig = sig + \addPoint.kr([0,0]);
25 | UMapOut.kr( sig, false );
26 | }, [ [ \index, 0, [0,1].asSpec], [ \trajectory, nil, WFSPathSpec() ], [ \addPoint, 0@0, WFSPointSpec(200, 0.1@0.1) ]])
27 | .category_( \point_utility )
28 | .canInsert_( false )
29 | .canUseUMapFunc_({ |unit, key, umapdef|
30 | unit.getSpec( key ).isKindOf( PointSpec );
31 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/lag_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \lag_point
3 |
4 | Creates an UMap for applying a lagging filter to point input. It's main purpose is to reduce unwanted doppler shift effects.
5 |
6 | point: the point to lag
7 | time: the time it will take for the point to travel to a new location
8 | linear: if true the lag will be a linear (ramp), if false (default) the lag is applied using a 3th order filter. The latter will produce less unnatural doppler shift changes.
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 |
16 | UMapDef( \lag_point, { |
17 | point = #[0.0, 0.0],
18 | time = 0.1,
19 | linear = 0
20 | |
21 | var lin, lag;
22 | lin = point.varlag( time );
23 | lag = point.lag3( time );
24 | point = LinXFade2.kr( lin, lag, linear.linlin(0,1,1,-1,\none) );
25 | UMapOut.kr(point, false);
26 | })
27 | .setSpec( \point, WFSPointSpec(200, 0.1) )
28 | .setSpec( \time, [0,10, 0.1.calcCurve ].asSpec )
29 | .setSpec( \linear, BoolSpec(false) )
30 | .category_( 'point_filter' )
31 | .canUseUMapFunc_({ |unit, key, umapdef|
32 | unit.getSpec( key ).isKindOf( PointSpec );
33 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/lag_polar.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \lag_polar
3 |
4 | Creates an UMap for applying a lagging filter to point input. It's main purpose is to reduce unwanted doppler shift effects. This polar version converts the position to polar values before applying the lag time, and provides separate timing controls for rho and theta. The rho value has more impact on doppler shift than the theta, so it makes sense to apply more lag on that.
5 |
6 | point: the point to lag
7 | timeRho: the time it will take the rho/distance of the point to change to a new value
8 | timeTheta: the time it will take the angle/theta of the point to change to a new valye
9 | linear: if true the lag will be a linear (ramp), if false (default) the lag is applied using a 3th order filter. The latter will produce less unnatural doppler shift changes.
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 |
17 | UMapDef( \lag_polar, { |
18 | point = #[0.0, 0.0],
19 | timeRho = 0.1,
20 | timeTheta = 0.1,
21 | linear = 0
22 | |
23 | var lin, lag;
24 | var polar;
25 | point = point.asPoint;
26 | polar = [ point.rho, Unwrap.kr( point.theta, -pi, pi) ];
27 | lin = polar.varlag( [timeRho, timeTheta] );
28 | lag = polar.lag3( [timeRho, timeTheta] );
29 | polar = LinXFade2.kr( lin, lag, linear.linlin(0,1,1,-1,\none) );
30 | polar = Polar( polar[0], polar[1] );
31 | point = [polar.real, polar.imag ];
32 | UMapOut.kr(point, false);
33 | })
34 | .setSpec( \point, WFSPointSpec(200, 0.1) )
35 | .setSpec( \timeRho, [0,10, 0.1.calcCurve ].asSpec )
36 | .setSpec( \timeTheta, [0,10, 0.1.calcCurve ].asSpec )
37 | .setSpec( \linear, BoolSpec(false) )
38 | .category_( 'point_filter' )
39 | .canUseUMapFunc_({ |unit, key, umapdef|
40 | unit.getSpec( key ).isKindOf( PointSpec );
41 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/line_trajectory.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \line_trajectory
3 |
4 | Creates an UMap for generating a line trajectory between two points. The points can also be UMaps.
5 |
6 | a: the start point of the line
7 | b: the end point of the line
8 | curve: a curve value (x,y) for the line. A 0 (zero) curve creates a linear line, a positive curve value makes the line tend towards the low value, and v.v.
9 | easeIn: a positive value makes the movement start slow, a negative value makes it start fast
10 | easeOut: a positive value makes the movement end slow, a negative value makes it end fast
11 | duration: duration of the line in seconds (can be modulated)
12 | loop: loopmode (0: off, 1: loop, 2: alternate)
13 | delay: delay time before the line starts
14 | trigger: a trigger that restarts the line
15 |
16 | --
17 | this is an UMapDef definition file
18 | part of the WFSCollider Class Library default UMapDefs set
19 | */
20 |
21 | UMapDef( \line_trajectory, { |
22 | a = #[0.0, 0.0],
23 | b = #[10.0,10.0],
24 | curve = #[0.0,0.0],
25 | easeIn = 0.0,
26 | easeOut = 0.0
27 | duration = 10|
28 | var line;
29 | line = ULine.kr( 0, 1, duration, \loop, \delay, \trigger );
30 | line = [0,1].splineIntFunction( line,
31 | easeIn.linlin(-1,1,2/3,0),
32 | easeOut.linlin(-1,1,1/3,1)
33 | );
34 | line = 2.collect({ |i|
35 | Select.kr( curve[i].inRange(-0.001,0.001), [
36 | line.lincurve(0,1, a[i], b[i], curve[i] ),
37 | line.linlin(0,1, a[i], b[i] )
38 | ]);
39 | });
40 | UMapOut.kr( line, false );
41 | })
42 | .category_( 'point_trajectory' )
43 | .canUseUMapFunc_({ |unit, key, umapdef|
44 | unit.getSpec( key ).isKindOf( PointSpec );
45 | })
46 | .setSpec( \a, WFSPointSpec(200) )
47 | .setSpec( \b, WFSPointSpec(200) )
48 | .setSpec( \curve, WFSPointSpec(16, 0.1) )
49 | .setSpec( \easeIn, [-1,1,\lin,0,0].asSpec )
50 | .setSpec( \easeOut, [-1,1,\lin,0,0].asSpec )
51 | .setSpec( \duration, SMPTESpec() )
52 | .setSpec( \delay, SMPTESpec() );
--------------------------------------------------------------------------------
/WFS/UMapDefs/map_control_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \map_control_point
3 |
4 | Creates an lightweight UMap that listens to two control bus from a previous unit in the chain and routes them directly to the point parameter it is connected to. No scaling or clipping is applied, so the user has to make sure that the bus contains data within the allowed input range.
5 |
6 | bus_x: the number of the control bus for x(usually 0)
7 | bus_y: the number of the control bus for y (usually 1)
8 |
9 | --
10 | this is an UMapDef definition file
11 | part of the Unit lib default UMapDefs set
12 | */
13 |
14 | FuncUMapDef( \map_control_point, { |unit, bus_x = 0, bus_y = 1|
15 | [ bus_x, bus_y ].collect({ |bus|
16 | ("c" ++ (bus + UIn.firstControlBus)).asSymbol
17 | });
18 | }, valueIsPrivate: true )
19 | .valueIsMapped_( false )
20 | .numChannels_(2)
21 | .allowedModes_([ 'normal', 'sync' ])
22 | .setSpec( \value, AnythingSpec() )
23 | .setSpec( \bus_x, PositiveIntegerSpec(0,0,31) )
24 | .setSpec( \bus_y, PositiveIntegerSpec(0,0,31) )
25 | .canUseUMapFunc_({ |unit, key, umapdef|
26 | unit.getSpec( key ).isKindOf( PointSpec )
27 | })
28 | .category_( 'private' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/map_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \map_point
3 |
4 | Creates an UMap allowing dynamic mapped access to x and y of a point
5 |
6 | x: position x (-1 - 1, 0 means center)
7 | y: position y (-1 - 1)
8 | center: center of the mapped area
9 | radius: radius of the mapped area
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the Unit lib default UMapDefs set
14 | */
15 |
16 | UMapDef( \map_point, { |
17 | x = 0,
18 | y = 0,
19 | center = #[0.0,0.0],
20 | radius = #[10.0,10.0]|
21 | UMapOut.kr([x,y] * radius + center, false );
22 | })
23 | .mappedArgs_( [] )
24 | .setSpec( \center, WFSPointSpec(200) )
25 | .setSpec( \radius, WFSRadiusSpec(200) )
26 | .setSpec( \x, [-1,1,\lin,0,0].asSpec )
27 | .setSpec( \y, [-1,1,\lin,0,0].asSpec )
28 | .category_( 'point_utility' )
29 | .canUseUMapFunc_({ |unit, key, umapdef|
30 | unit.getSpec( key ).isKindOf( PointSpec );
31 | });
32 |
--------------------------------------------------------------------------------
/WFS/UMapDefs/map_polar.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \map_polar
3 |
4 | Creates an UMap intended for use on modulatable point parameters. It converts the point into a polar, with linear controls for rho and theta, which on their turn can be used to assign other UMaps to. The point is mapped to a circle or ellipse with settable center and radius.
5 |
6 | rho: the rho value (0-1)
7 | theta: the theta value (angle in radians)
8 | center: center of the mapped area
9 | radius: radius of the mapped area
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the Unit lib default UMapDefs set
14 | */
15 |
16 | UMapDef( \map_polar, { |
17 | rho = 0.0,
18 | theta = 0,
19 | center = #[0.0,0.0],
20 | radius = #[10.0,10.0]|
21 | var polar;
22 | polar = Polar( rho, theta );
23 | x = polar.real;
24 | y = polar.imag;
25 | UMapOut.kr([polar.real, polar.imag] * radius + center, false );
26 | })
27 | .setSpec( \theta, AngleSpec() )
28 | .setSpec( \rho, [-1,1,\lin,0,0].asSpec )
29 | .setSpec( \center, WFSPointSpec(200) )
30 | .setSpec( \radius, WFSRadiusSpec(200) )
31 | .category_( 'point_utility' )
32 | .canUseUMapFunc_({ |unit, key, umapdef|
33 | unit.getSpec( key ).isKindOf( PointSpec );
34 | });
35 |
--------------------------------------------------------------------------------
/WFS/UMapDefs/mirror_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \mirror_point
3 |
4 | Creates an UMap intended that mirrors a point across a line. This can be used for example for creating early reflection positions.
5 |
6 | point: the point to rotate (can be an UMap)
7 | plane: the line/plane across which the point is mirrored.
8 | absolute: if true, the point will only be mirrored when it is in front of the line, and thus the mirrored point will always stay behind the line.
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the Unit lib default UMapDefs set
13 | */
14 |
15 | UMapDef( \mirror_point, { |point = #[0.0,0.0], plane = #[5.0,0.0], absolute = 0|
16 | var newX;
17 | point = point.asPoint;
18 | plane = plane.asPoint.asPolar;
19 | point = point.rotate( plane.theta.neg );
20 | newX = point.x.neg + (2 * plane.rho);
21 | newX = Select.kr( absolute, [ newX, newX.max( point.x ) ] );
22 | point = Point( newX, point.y ).rotate( plane.theta );
23 | UMapOut.kr(point.asArray, false);
24 | })
25 | .setSpec( \point, WFSPointSpec(200,0.1) )
26 | .setSpec( \plane, WFSPlaneSpec(200,0.1) )
27 | .setSpec( \absolute, BoolSpec( false ) )
28 | .category_( 'point_utility' )
29 | .canUseUMapFunc_({ |unit, key, umapdef|
30 | unit.getSpec( key ).isKindOf( PointSpec );
31 | });
32 |
--------------------------------------------------------------------------------
/WFS/UMapDefs/motion_trajectory.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \motion_trajectory
3 |
4 | Creates an UMap for generating a motion based on speed and acceleration, contained in a rectangular area.
5 |
6 | startPoint: start point of the movement, can be changed over time
7 | startSpeed: initial speed, can be changed over time to produce relative speed changes
8 | acceleration: (in m/s^2) amount of acceleration over x and y axes
9 | center: the center of the clipping area
10 | radius: the radius of the clipping area
11 | clipMode: can be one of the following modes:
12 | 0 - 'clip': clip coordinates outside clipping area
13 | 1 - 'fold' (default): fold/mirror coordinates outside clipping area - this produces a typical hard wall bounce
14 | 2 - 'wrap': wrap around coordinates outside clipping area
15 | 3 - 'none': no clipping applied (values can go outside clipping area)
16 | clipSoftness: softens the edges of 'clip' and 'fold' modes.
17 | reset: jump to startPoint/startSpeed
18 |
19 | note: There may be floating precision issues when running this for a very long time.
20 |
21 | --
22 | this is an UMapDef definition file
23 | part of the Unit lib default UMapDefs set
24 | */
25 |
26 |
27 | UMapDef( \motion_trajectory, { |
28 | startPoint = #[0.0, 0.0],
29 | startSpeed = #[1.0, 1.0],
30 | acceleration = #[0.0, 0.0],
31 | center = #[0.0, 0.0],
32 | radius = #[10.0, 10.0],
33 | clipMode = 1,
34 | clipSoftness = 0.1|
35 | var point, speed;
36 | var reset;
37 | reset = \reset.utr + Impulse.kr(0);
38 | radius = radius.max(1.0e-10);
39 |
40 | speed = Sweep.kr( reset, acceleration ) + startSpeed;
41 | point = Sweep.kr( reset, speed ) + startPoint;
42 |
43 | point = point - center;
44 | point = point.linlin( radius.neg, radius, -1, 1, \none );
45 | point = Select.kr( clipMode, [
46 | point.softclip2(1, clipSoftness),
47 | point.softfold2(1, clipSoftness),
48 | point.wrap2(1),
49 | point
50 | ]);
51 | point = point.linlin( -1, 1, radius.neg, radius, \none ) + center;
52 | UMapOut.kr(point, false);
53 | })
54 | .setSpec( \startPoint, WFSPointSpec(200) )
55 | .setSpec( \startSpeed, WFSPointSpec(200) )
56 | .setSpec( \acceleration, WFSPointSpec(200) )
57 | .setSpec( \center, WFSPointSpec(200) )
58 | .setSpec( \radius, WFSRadiusSpec(Rect(0,0,200,200)) )
59 | .setSpec( \clipMode, ListSpec( (..3), 1, [ \clip, \fold, \wrap, \none ] ) )
60 | .setSpec( \clipSoftness, [0,1,\lin,0,0.1].asSpec )
61 | .category_( 'point_trajectory' )
62 | .canUseUMapFunc_({ |unit, key, umapdef|
63 | unit.getSpec( key ).isKindOf( PointSpec );
64 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_circle_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_circle_point
3 |
4 | Creates an pattern UMap for a circular movement of points. New values are generated each time the chain is started, or in a UPattern for each of the generated events.
5 |
6 | speed: speed in periods per next point
7 | startAngle: the start angle in radians
8 | clockwise: rotate clockwise if true, counterclockwise if false
9 | center: center of the circle
10 | radius: radius of the circle (can be an ellipse too)
11 |
12 | --
13 | this is an UMapDef definition file
14 | part of the WFSCollider Class Library default UMapDefs set
15 | */
16 |
17 | UPatDef( \p_circle_point, { |unit,
18 | speed = 0.1,
19 | startAngle = 0,
20 | clockwise = true,
21 | center = (0@0),
22 | radius = (10@10)
23 | timeBase = \seconds|
24 | {
25 | var i = 0;
26 | var timer = UPattern.deltaTimer;
27 | var spd;
28 | if( timeBase.next === \seconds ) {
29 | spd = speed.next * clockwise.next.binaryValue.linlin(0,1,-1,1);
30 | i = spd * UPattern.startPos;
31 | };
32 | loop {
33 | ((((((i % 1) * 2pi) + [0, 0.5pi] + startAngle.next).sin
34 | * radius.next.asArray) + center.next.asArray))
35 | .asPoint.yield;
36 | spd = speed.next * clockwise.next.binaryValue.linlin(0,1,-1,1);
37 | switch( timeBase.next,
38 | \events, { i = i + spd },
39 | \seconds, { i = i + (spd * timer.value); },
40 | );
41 | };
42 | }.r
43 | }).category_( 'pattern_point' )
44 | .valueIsMapped_( false )
45 | .numChannels_( 2 )
46 | .setSpec( \value, DisplaySpec( PointSpec(Rect(0,0,1,1)), { |point|
47 | "% @ %".format(point.x, point.y )
48 | }) )
49 | .setDefault( \value, 0.0@0.0 )
50 | .setDefault( \center, 0.0@0.0 )
51 | .setDefault( \radius, 10@10 )
52 | .setSpec( \speed, [ 0, 100, 99.squared.log, 0, 0.1 ].asSpec )
53 | .setSpec( \startAngle, AngleSpec() )
54 | .setSpec( \clockwise, BoolSpec( true ) )
55 | .setSpec( \center, WFSPointSpec(200) )
56 | .setSpec( \radius, WFSRadiusSpec(200) )
57 | .setSpec( \timeBase, ListSpec( [ 'events', 'seconds' ] ) )
58 | .canUseUMapFunc_({ |unit, key, umapdef|
59 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
60 | unit.getSpec( key ).isMemberOf( class )
61 | });
62 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_envir_point_get.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_envir_point_get
3 |
4 | Creates an pattern UMap for getting environment variables. Use in conjunction with the 'envir_set' Udef. Environment values are also accessible via regular SuperCollider code, by adding a '~' in front of the name.
5 |
6 | key: the name of the variable (default: 'a')
7 |
8 | The value will automatically be scaled to the value range of the parameter to which the UMap is connected.
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UPatDef( \p_envir_point_get, { |unit, key = 'p', index = 0|
16 | {
17 | var kkey, val, spec, fromSpec, ii = 0;
18 | spec = unit.spec ?? { WFSPointSpec(200) };
19 | loop {
20 | kkey = key.next.asSymbol;
21 | if( kkey.notNil ) {
22 | val = currentEnvironment[ kkey ] ? (spec.default);
23 | fromSpec = currentEnvironment[ \u_specs ] !? _[ kkey ] ? spec;
24 | if( val.isCollection ) {
25 | val = val.wrapAt( ii );
26 | ii = ii+1;
27 | };
28 | if( val.isKindOf( Point ).not ) {
29 | val = spec.constrain( val.asPoint );
30 | };
31 | } {
32 | val = spec.default;
33 | };
34 | val.yield;
35 | };
36 | }.r
37 | })
38 | .setSpec( \key, EnvirSpec() )
39 | .setSpec( \index, IntegerSpec(0,0,1024) )
40 | .numChannels_( 2 )
41 | .valueIsMapped_( false )
42 | .mappedArgs_([])
43 | .canUseUMapFunc_({ |unit, key, umapdef|
44 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
45 | unit.getSpec( key ).isMemberOf( class )
46 | });
47 | })
48 | .category_( 'pattern_envir' );
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_line_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_line
3 |
4 | Creates an pattern UMap making a line trajectory. New values are generated each time the chain is started, or in a UPattern for each of the generated events.
5 |
6 | a: the start point
7 | b: the end point
8 | curve: a curve value (x,y) for the line. A 0 (zero) curve creates a linear line, a positive curve
9 | value makes the line tend towards the low value, and v.v.
10 | easeIn: a positive value makes the movement start slow, a negative value makes it start fast
11 | easeOut: a positive value makes the movement end slow, a negative value makes it end fast
12 | time: time to it takes from a to b;
13 | loop: loop mode;
14 | \off: no looping (will stay at end value after completing)
15 | \loop: (default) wrap around between lo and hi
16 | \backwards: loop backwards
17 | \alternate: move back and forth between lo and hi
18 |
19 | The 'lo' and 'hi' arg ranges are mapped to that of the parameter to which the UMap is connected
20 |
21 | --
22 | this is an UMapDef definition file
23 | part of the WFSCollider Class Library default UMapDefs set
24 | */
25 |
26 | UPatDef( \p_line_point, { |unit,
27 | a = (0@0),
28 | b = (10@10),
29 | curve = (0.0@0.0),
30 | easeIn = 0.0,
31 | easeOut = 0.0,
32 | time = 10,
33 | loop = \loop|
34 | {
35 | var current = 0, direction = 1;
36 | var timer = UPattern.deltaTimer;
37 | var aa, bb, ccurve;
38 | if( loop.next === \backwards ) { direction = -1; current = 1; };
39 | inf.do { |i|
40 | aa = a.next.asArray;
41 | bb = b.next.asArray;
42 | ccurve = curve.next.asArray;
43 | [0,1].splineIntFunction( current,
44 | easeIn.next.linlin(-1,1,2/3,0),
45 | easeOut.next.linlin(-1,1,1/3,1)
46 | ).dup.collect({ |item, i|
47 | item.lincurve(0,1, aa[i], bb[i], ccurve[i]);
48 | }).asPoint.yield;
49 | current = (current + ((direction * timer.value/time.next).clip2( 1.0e12 )));
50 | switch( loop.next,
51 | \loop, { current = current.wrap( 0.0, 1.0 ); direction = 1 },
52 | \backwards, { current = current.wrap( 0.0, 1.0 ); direction = -1; },
53 | \alternate, {
54 | case { current > 1 } {
55 | current = current.fold(0.0,1.0);
56 | direction = -1;
57 | } { current < 0 } {
58 | current = current.fold(0.0,1.0);
59 | direction = 1;
60 | };
61 | },
62 | \off, { current = current.clip(0.0,1.0); }
63 | );
64 | };
65 | }.r;
66 | })
67 | .valueIsMapped_( false )
68 | .numChannels_( 2 )
69 | .setSpec( \value, DisplaySpec( PointSpec(Rect(0,0,1,1)), { |point|
70 | "% @ %".format(point.x, point.y )
71 | }) )
72 | .setDefault( \value, 0.0@0.0 )
73 | .setDefault( \a, 0.0@0.0 )
74 | .setDefault( \b, 10@10 )
75 | .setDefault( \curve, 0@0 )
76 | .setSpec( \a, WFSPointSpec(200) )
77 | .setSpec( \b, WFSPointSpec(200) )
78 | .setSpec( \curve, WFSPointSpec(200) )
79 | .setSpec( \time, SMPTESpec() )
80 | .setSpec( \loop, ListSpec( [ \off, \loop, \backwards, \alternate ], 1 ) )
81 | .category_( 'pattern_point' )
82 | .canUseUMapFunc_({ |unit, key, umapdef|
83 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
84 | unit.getSpec( key ).isMemberOf( class )
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_map_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_map_point
3 |
4 | Creates an pattern UMap allowing mapped access to x and y of a point
5 |
6 | x: position x (-1 - 1, 0 means center)
7 | y: position y (-1 - 1)
8 | center: center of the mapped area
9 | radius: radius of the mapped area
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 | UPatDef( \p_map_point, { |unit,
17 | x = 0,
18 | y = 0,
19 | center = (0@0),
20 | radius = (10@10)|
21 | {
22 | loop {
23 | ([x.next, y.next] * radius.next.asArray + center.next.asArray).asPoint.yield
24 | };
25 | }.r
26 | }).category_( 'pattern_point' )
27 | .valueIsMapped_( false )
28 | .numChannels_( 2 )
29 | .setSpec( \value, DisplaySpec( PointSpec(Rect(0,0,1,1)), { |point|
30 | "% @ %".format(point.x, point.y )
31 | }) )
32 | .setSpec( \center, WFSPointSpec(200) )
33 | .setSpec( \radius, WFSRadiusSpec(200) )
34 | .setDefault( \radius, 10@10 )
35 | .setSpec( \x, [-1,1,\lin,0,0].asSpec )
36 | .setSpec( \y, [-1,1,\lin,0,0].asSpec )
37 | .canUseUMapFunc_({ |unit, key, umapdef|
38 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
39 | unit.getSpec( key ).isMemberOf( class )
40 | });
41 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_map_polar.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_map_polar
3 |
4 | Creates an pattern UMap for converting angle and distance (rho, theta) to a cartesian point
5 |
6 | rho: distance from center (0-1)
7 | theta: angle (-pi - pi)
8 | center: center of the mapped area
9 | radius: radius of the mapped area
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 | UPatDef( \p_map_polar, { |unit,
17 | rho = 0,
18 | theta = 0,
19 | center = (0@0),
20 | radius = (10@10)|
21 | {
22 | loop {
23 | (Polar(rho.next, theta.next).asPoint.asArray * radius.next.asArray + center.next.asArray).asPoint.yield
24 | };
25 | }.r
26 | }).category_( 'pattern_point' )
27 | .valueIsMapped_( false )
28 | .numChannels_( 2 )
29 | .setSpec( \value, DisplaySpec( PointSpec(Rect(0,0,1,1)), { |point|
30 | "% @ %".format(point.x, point.y )
31 | }) )
32 | .setSpec( \center, WFSPointSpec(200) )
33 | .setSpec( \radius, WFSRadiusSpec(200) )
34 | .setDefault( \radius, 10@10 )
35 | .setSpec( \rho, [0,1,\lin,0,0].asSpec )
36 | .setSpec( \theta, AngleSpec() )
37 | .canUseUMapFunc_({ |unit, key, umapdef|
38 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
39 | unit.getSpec( key ).isMemberOf( class )
40 | });
41 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_randomwalk_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_randomwalk_point
3 |
4 | Creates a random walk movement for UPatterns with (WFS) Point arguments. The walk starts at 'startPoint' and goes in random steps from there. The algorithm is tuned in such a way that it gravitates to the 'center' and tries to stay within the 'radius'. If the startPoint or next point for some reason is outside the center/radius area the point will try to walk back in. center, radius and stepSize can all be changed during the walk, but startPoint is only used at the start.
5 |
6 | startPoint: the first point. This will only be polled once per time the pattern plays
7 | stepSize: a range from 0-1, indicating the possible step sizes relative to the radius
8 | center: center of the area where the random walk takes place
9 | radius: radius of the area where the random walk takes place
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 | UPatDef( \p_randomwalk_point, { |unit,
17 | startPoint = (0@0),
18 | stepSize = #[0,1],
19 | center = (0@0),
20 | radius = (10@10)|
21 | {
22 | var point, step, rradius, ccenter, scaledPoint;
23 | point = startPoint.next.asPoint; // only polled once
24 | point.yield;
25 | loop {
26 | rradius = radius.next.asPoint;
27 | ccenter = center.next.asPoint;
28 | step = stepSize.next;
29 | step = (step[0].asFloat rrand: step[1]) @ (step[0].asFloat rrand: step[1]);
30 | step = step * rradius;
31 | scaledPoint = ( point.x.linlin( ccenter.x - rradius.x, ccenter.x + rradius.x, 0, 1 ) ) @
32 | ( point.y.linlin( ccenter.y - rradius.y, ccenter.y + rradius.y, 0, 1 ) );
33 | step = step * (( if( scaledPoint.x.coin ) { -1 } { 1 } ) @ ( if( scaledPoint.y.coin ) { -1 } { 1 } ));
34 | point = point + step;
35 | point.yield;
36 | };
37 | }.r
38 | }).category_( 'pattern_point' )
39 | .valueIsMapped_( false )
40 | .numChannels_( 2 )
41 | .setSpec( \value, DisplaySpec( PointSpec(Rect(0,0,1,1)), { |point|
42 | "% @ %".format(point.x, point.y )
43 | }) )
44 | .setDefault( \value, 0.0@0.0 )
45 | .setDefault( \center, 0.0@0.0 )
46 | .setDefault( \radius, 10@10 )
47 | .setDefault( \startPoint, 0.0@0.0 )
48 | .setSpec( \stepSize, RangeSpec(0,1) )
49 | .setSpec( \center, WFSPointSpec(200) )
50 | .setSpec( \radius, WFSRadiusSpec(200) )
51 | .setSpec( \startPoint, WFSPointSpec(200) )
52 | .canUseUMapFunc_({ |unit, key, umapdef|
53 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
54 | unit.getSpec( key ).isMemberOf( class )
55 | });
56 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/p_sequencer_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \p_sequencer_point
3 |
4 | Creates an pattern UMap for sequencing a group of points. The next point is chosen each time the chain is started, or in a UPattern for each of the generated events.
5 |
6 | points: a WFSPointGroup containing the points to sequence
7 | loop: loop mode;
8 | \off: loop once and stay at last point
9 | \loop: loop from first to last
10 | \backwards: loop from last to first
11 | \alternate: loop forwards and backwards
12 |
13 | --
14 | this is an UMapDef definition file
15 | part of the WFSCollider Class Library default UMapDefs set
16 | */
17 |
18 | UPatDef( \p_sequencer_point, { |unit,
19 | points,
20 | loop = \loop|
21 |
22 | {
23 | var current = 0, direction = 1;
24 | points.next.wrapAt( current ).yield;
25 | inf.do { |i|
26 | var pointsNext, size = 0;
27 | current = current + direction;
28 | pointsNext = points.next;
29 | if( pointsNext.notNil ) {
30 | size = pointsNext.size;
31 | };
32 | switch( loop.next,
33 | \loop, { current = current.wrap( 0, size -1); direction = 1; },
34 | \backwards, { current = current.wrap( 0, size -1); direction = -1; },
35 | \alternate, {
36 | case { current >= size} {
37 | current = current.fold(0,size-1);
38 | direction = -1;
39 | } { current < 0 } {
40 | current = current.fold(0,size-1);
41 | direction = 1;
42 | };
43 | },
44 | \random, {
45 | current = size.rand;
46 | },
47 | \off, { current = current.clip(0,size-1); direction = 1; }
48 | );
49 | pointsNext.wrapAt( current ).yield;
50 | };
51 | }.r
52 | }).category_( 'pattern_point' )
53 | .valueIsMapped_( false )
54 | .numChannels_( 2 )
55 | .setSpec( \loop, ListSpec( [ \off, \loop, \backwards, \alternate, \random ], 1 ) )
56 | .setDefault( \value, 0.0@0.0 )
57 | .setSpec( \points, WFSMultiPointSpec( 200, default: WFSPointGroup.generate( 8, \circle ).positions ) )
58 | .setDefault( \points, WFSPointGroup.generate( 8, \circle ).positions )
59 | .canUseUMapFunc_({ |unit, key, umapdef|
60 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
61 | unit.getSpec( key ).isMemberOf( class )
62 | });
63 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_angle.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \point_angle
3 |
4 | Creates an UMap for converting the angle between two points (or point UMaps) to a value range.
5 |
6 | point1: the first point
7 | point2: the second point
8 | centerAngle: the reference angle (subtracted from the absolute angle)
9 | fromRange: the angle range from which the output value will be calculated, divided by pi
10 | toRange: the value range to which the angle range will be mapped
11 | invert: (boolean) if true the angle range will be inverted
12 | clipMode: when the angle is outside the fromRange, the clipMode decides what happens. The angle is "unwrapped" internally, so if the point would for example spin multiple times it will go outside the clipping area.
13 | 0 - 'clip': clip inside the value range
14 | 1 - 'fold': fold/mirror inside the value range
15 | 2 - 'wrap' (default): wrap around the value range
16 | 3 - 'none': no clipping applied (values can go outside the value range)
17 | clipSoftness: softens the edges of 'clip' and 'fold' modes (0-1).
18 |
19 | The toRange arg range is mapped to that of the parameter to which the UMap is connected.
20 |
21 | --
22 | this is an UMapDef definition file
23 | part of the WFSCollider Class Library default UMapDefs set
24 | */
25 |
26 | UMapDef( \point_angle, { |
27 | point1 = #[0.0, 0.0],
28 | point2 = #[0.0, 0.0],
29 | centerAngle = 0,
30 | fromRange = #[-1, 1],
31 | toRange = #[0.0,1.0],
32 | invert = 0,
33 | clipMode = 2,
34 | clipSoftness = 0.0|
35 | var angle;
36 | angle = (point1 - point2).asPoint.angle - centerAngle;
37 | angle = angle.wrap(-pi, pi).unwrap(-pi,pi);
38 | angle = angle.linlin( *(fromRange * pi) ++ [-1,1, \none ] );
39 | angle = angle * invert.linlin(0,1,1,-1,\none);
40 | angle = Select.kr( clipMode, [
41 | angle.softclip2(1, clipSoftness ),
42 | angle.softfold2(1, clipSoftness ),
43 | angle.wrap2(1),
44 | angle
45 | ]);
46 | angle = angle.linlin( -1, 1, *toRange ++ [\none] );
47 | UMapOut.kr( angle );
48 | })
49 | .mappedArgs_( [ \toRange ] )
50 | .setSpec( \point1, WFSPointSpec(200) )
51 | .setSpec( \point2, WFSPointSpec(200) )
52 | .setSpec( \centerAngle, AngleSpec() )
53 | .setSpec( \fromRange, [-1,1].asSpec.asRangeSpec )
54 | .setSpec( \invert, BoolSpec(false) )
55 | .setSpec( \clipMode, ListSpec( (..3), 0, [ \clip, \fold, \wrap, \none ] ) )
56 | .setSpec( \clipSoftness, [0,1,\lin,0,0.0].asSpec )
57 | .category_( 'point_to_value' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_axis.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \point_axis
3 |
4 | Creates an UMap for converting a point (or point UMap) to a single value, by projecting it on a line. The line can be the x axis (default) or y axis, but via the 'rotate' argument it can also be somewhere in between.
5 |
6 | point: the point
7 | which: the axis to project on
8 | rotate: amount of rotation (to deviate from the axis)
9 | fromRange: the range from which the output value will be calculated
10 | toRange: the value range to which the range will be mapped
11 | clipMode: when the value is outside the fromRange, the clipMode decides what happens
12 | 0 - 'clip' (default): clip inside the value range
13 | 1 - 'fold': fold/mirror inside the value range
14 | 2 - 'wrap': wrap around the value range
15 | 3 - 'none': no clipping applied (values can go outside the value range)
16 | clipSoftness: softens the edges of 'clip' and 'fold' modes (0-1).
17 |
18 | The 'toRange' arg range is mapped to that of the parameter to which the UMap is connected.
19 |
20 | --
21 | this is an UMapDef definition file
22 | part of the WFSCollider Class Library default UMapDefs set
23 | */
24 |
25 |
26 | UMapDef( \point_axis, { |
27 | point = #[0.0, 0.0],
28 | which = 0,
29 | rotate = 0,
30 | fromRange = #[-20, 20],
31 | toRange = #[0.0,1.0],
32 | clipMode = 0,
33 | clipSoftness = 0.0|
34 | var value;
35 | point = point.asPoint.rotate(rotate).asArray;
36 | value = Select.kr( which, point ++ point.neg );
37 | value = value.linlin( *fromRange ++ [-1,1, \none ] );
38 | value = Select.kr( clipMode, [
39 | value.softclip2(1, clipSoftness ),
40 | value.softfold2(1, clipSoftness ),
41 | value.wrap2(1),
42 | value
43 | ]);
44 | value = value.linlin( -1, 1, *toRange ++ [\none] );
45 | UMapOut.kr( value );
46 | })
47 | .mappedArgs_( [ \toRange ] )
48 | .setSpec( \point, WFSPointSpec(200) )
49 | .setSpec( \which, ListSpec( (..3), 0, [ \x, \y, '-x', '-y' ] ) )
50 | .setSpec( \rotate, AngleSpec( -0.5pi, 0.5pi ) )
51 | .setSpec( \fromRange, [-200,200].asSpec.asRangeSpec )
52 | .setSpec( \clipMode, ListSpec( (..3), 0, [ \clip, \fold, \wrap, \none ] ) )
53 | .setSpec( \clipSoftness, [0,1,\lin,0,0.0].asSpec )
54 | .category_( 'point_to_value' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_direction.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \point_direction
3 |
4 | Creates an UMap for getting the direction angle of a moving point.
5 |
6 | point: the point
7 | centerAngle: the reference angle (subtracted from the absolute angle)
8 | fromRange: the angle range from which the output value will be calculated, divided by pi
9 | toRange: the value range to which the angle range will be mapped
10 | invert: (boolean) if true the angle range will be inverted
11 | clipMode: when the angle is outside the fromRange, the clipMode decides what happens. The angle is "unwrapped" internally, so if the point would for example spin multiple times it will go outside the clipping area.
12 | 0 - 'clip': clip inside the value range
13 | 1 - 'fold': fold/mirror inside the value range
14 | 2 - 'wrap' (default): wrap around the value range
15 | 3 - 'none': no clipping applied (values can go outside the value range)
16 | clipSoftness: softens the edges of 'clip' and 'fold' modes (0-1).
17 | lag: linear lag time for output
18 |
19 | The toRange arg range is mapped to that of the parameter to which the UMap is connected.
20 |
21 | --
22 | this is an UMapDef definition file
23 | part of the WFSCollider Class Library default UMapDefs set
24 | */
25 |
26 | UMapDef( \point_direction, { |
27 | point = #[0.0, 0.0],
28 | centerAngle = 0,
29 | fromRange = #[-1, 1],
30 | toRange = #[0.0,1.0],
31 | invert = 0,
32 | clipMode = 2,
33 | clipSoftness = 0.0,
34 | lag = 0.0|
35 | var angle, lastPoint;
36 | lastPoint = Delay1.kr( point );
37 | angle = (point - lastPoint).asPoint.angle - centerAngle;
38 | angle = Gate.kr( angle, point.asPoint.dist( lastPoint ) > 0 );
39 | angle = angle.wrap(-pi, pi).unwrap(-pi,pi).lag3(lag);
40 | angle = angle.linlin( *(fromRange * pi) ++ [-1,1, \none ] );
41 | angle = angle * invert.linlin(0,1,1,-1,\none);
42 | angle = Select.kr( clipMode, [
43 | angle.softclip2(1, clipSoftness ),
44 | angle.softfold2(1, clipSoftness ),
45 | angle.wrap2(1),
46 | angle
47 | ]);
48 | angle = angle.linlin( -1, 1, *toRange ++ [\none] );
49 | UMapOut.kr( angle );
50 | })
51 | .mappedArgs_( [ \toRange ] )
52 | .setSpec( \point, WFSPointSpec(200,0.1) )
53 | .setSpec( \centerAngle, AngleSpec() )
54 | .setSpec( \fromRange, [-1,1].asSpec.asRangeSpec )
55 | .setSpec( \invert, BoolSpec(false) )
56 | .setSpec( \clipMode, ListSpec( (..3), 0, [ \clip, \fold, \wrap, \none ] ) )
57 | .setSpec( \clipSoftness, [0,1,\lin,0,0.0].asSpec )
58 | .category_( 'point_to_value' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_distance.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \point_distance
3 |
4 | Creates an UMap for converting the distance between two points (or point UMaps) to a value range.
5 |
6 | point1: the first point
7 | point2: the second point
8 | fromRange: the distance range from which the output value will be calculated
9 | toRange: the value range to which the distance range will be mapped
10 | invert: (boolean) if true the distance range will be inverted
11 | clipMode: when the distance is outside the fromRange, the clipMode decides what happens
12 | 0 - 'clip' (default): clip inside the value range
13 | 1 - 'fold': fold/mirror inside the value range
14 | 2 - 'wrap': wrap around the value range
15 | 3 - 'none': no clipping applied (values can go outside the value range)
16 | clipSoftness: softens the edges of 'clip' and 'fold' modes (0-1).
17 |
18 | The toRange arg range is mapped to that of the parameter to which the UMap is connected.
19 |
20 | --
21 | this is an UMapDef definition file
22 | part of the WFSCollider Class Library default UMapDefs set
23 | */
24 |
25 | UMapDef( \point_distance, { |
26 | point1 = #[0.0, 0.0],
27 | point2 = #[0.0, 0.0],
28 | fromRange = #[0, 20],
29 | toRange = #[0.0,1.0],
30 | invert = 0,
31 | clipMode = 0,
32 | clipSoftness = 0.0|
33 | var dist;
34 | dist = point1.asPoint.dist( point2.asPoint );
35 | dist = dist.linlin( *fromRange ++ [-1,1, \none ] );
36 | dist = dist * invert.linlin(0,1,1,-1,\none);
37 | dist = Select.kr( clipMode, [
38 | dist.softclip2(1, clipSoftness ),
39 | dist.softfold2(1, clipSoftness ),
40 | dist.wrap2(1),
41 | dist
42 | ]);
43 | dist = dist.linlin( -1, 1, *toRange ++ [\none] );
44 | UMapOut.kr( dist );
45 | })
46 | .mappedArgs_( [ \toRange ] )
47 | .setSpec( \point1, WFSPointSpec(200) )
48 | .setSpec( \point2, WFSPointSpec(200) )
49 | .setSpec( \fromRange, [0,400].asSpec.asRangeSpec )
50 | .setSpec( \invert, BoolSpec(false) )
51 | .setSpec( \clipMode, ListSpec( (..3), 0, [ \clip, \fold, \wrap, \none ] ) )
52 | .setSpec( \clipSoftness, [0,1,\lin,0,0.1].asSpec )
53 | .category_( 'point_to_value' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_in_rect.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \point_in_rect
3 |
4 | Creates an UMap for testing if a point is inside or outside a rectangle.
5 |
6 | point: the point
7 | center: the center of the rect area
8 | radius: the radius of the rect area
9 | inValue: the value to return when the point is inside the rect
10 | outValue: the value to return when the point is outside the rect
11 |
12 | The 'inValue' and 'outValue' arg range is mapped to that of the parameter to which the UMap is connected.
13 |
14 | --
15 | this is an UMapDef definition file
16 | part of the WFSCollider Class Library default UMapDefs set
17 | */
18 |
19 | UMapDef( \point_in_rect, { |
20 | point = #[0.0, 0.0],
21 | center = #[0.0, 0.0],
22 | radius = #[10.0, 10.0],
23 | inValue = 1.0,
24 | outValue = 0.0|
25 | var index, output;
26 | var rangeX, rangeY;
27 | rangeX = center[0] + (radius[0] * [-1,1]);
28 | rangeY = center[1] + (radius[1] * [-1,1]);
29 | index = InRange.kr( point[0], *rangeX ) * InRange.kr( point[1], *rangeY );
30 | output = Select.kr( index, [ outValue, inValue ] );
31 | UMapOut.kr( output );
32 | })
33 | .setSpec( \point, WFSPointSpec(200) )
34 | .setSpec( \center, WFSPointSpec(200) )
35 | .setSpec( \radius, WFSRadiusSpec(Rect(0,0,200,200)) )
36 | .mappedArgs_([ \inValue, \outValue ])
37 | .category_( 'point_to_value' );
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_poll.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \poll_point
3 |
4 | An UMap that posts incoming point in the 'post' window. The point itself is passed through unchanged.
5 |
6 | point: the point to be posted
7 | trigger: a trigger causes the value to be posted
8 | onChange: when true, the value will be posted whenever it changes (can result in many posts)
9 | speed: number of times per second to post the value automatically (default 0 - no automatic posting).
10 |
11 | The value arg range is mapped to that of the parameter to which the UMap is connected.
12 |
13 | --
14 | this is an UMapDef definition file
15 | part of the WFSCollider-Class-Library default UMapDefs set
16 | */
17 |
18 | UMapDef( \poll_point, { |point = #[0.0, 0.0]|
19 | var speed, trigger, change, onChange, mappedVal;
20 | trigger = \trigger.tr( 1 );
21 | onChange = \onChange.kr( 0 );
22 | speed = \speed.kr( 0 );
23 | change = HPZ1.kr( point.sum ).abs > 0;
24 | change = (HPZ1.kr( change ).abs > 0) + (TDuty.kr( 0.1, change ) * change);
25 | change = change * onChange;
26 | Poll.kr( Impulse.kr( speed ) + trigger + change,
27 | point,
28 | "poll_point" );
29 | UMapOut.kr(point, false);
30 | })
31 | .setSpec( \point, WFSPointSpec(200, 0.1) )
32 | .setSpec( \onChange, BoolSpec( false ) )
33 | .setSpec( \speed, [0,20,\lin,0,0].asSpec )
34 | .setSpec( \trigger, TriggerSpec( ) )
35 | .canUseUMapFunc_({ |unit, key, umapdef|
36 | unit.getSpec( key ).isKindOf( PointSpec );
37 | })
38 | .category_( 'point_utility' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/point_speed.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \point_speed
3 |
4 | Creates an UMap for measuring the speed of a point (or point UMap) and convert it to a value.
5 |
6 | point: the point
7 | fromRange: the speed range from which the output value will be calculated
8 | toRange: the value range to which the speed range will be mapped
9 | clipMode: when the speed is outside the fromRange, the clipMode decides what happens
10 | 0 - 'clip' (default): clip inside the value range
11 | 1 - 'fold': fold/mirror inside the value range
12 | 2 - 'wrap': wrap around the value range
13 | 3 - 'none': no clipping applied (values can go outside the value range)
14 | clipSoftness: softens the edges of 'clip' and 'fold' modes (0-1).
15 |
16 | The 'toRange' arg range is mapped to that of the parameter to which the UMap is connected.
17 |
18 | --
19 | this is an UMapDef definition file
20 | part of the WFSCollider Class Library default UMapDefs set
21 | */
22 |
23 |
24 | UMapDef( \point_speed, { |
25 | point = #[0.0, 0.0],
26 | fromRange = #[0, 20],
27 | toRange = #[0.0,1.0],
28 | clipMode = 0,
29 | clipSoftness = 0.0|
30 | var value;
31 | value = ((point - Delay1.kr( point )) * ControlRate.ir).asPoint.rho;
32 | value = value.linlin( *fromRange ++ [-1,1, \none ] );
33 | value = Select.kr( clipMode, [
34 | value.softclip2(1, clipSoftness ),
35 | value.softfold2(1, clipSoftness ),
36 | value.wrap2(1),
37 | value
38 | ]);
39 | value = value.linlin( -1, 1, *toRange ++ [\none] );
40 | UMapOut.kr( value );
41 | })
42 | .mappedArgs_( [ \toRange ] )
43 | .setSpec( \point, WFSPointSpec(200,0.1) )
44 | .setSpec( \fromRange, [0,344].asSpec.asRangeSpec )
45 | .setSpec( \clipMode, ListSpec( (..3), 0, [ \clip, \fold, \wrap, \none ] ) )
46 | .setSpec( \clipSoftness, [0,1,\lin,0,0.0].asSpec )
47 | .category_( 'point_to_value' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/random_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \random_point
3 |
4 | Creates an UMap that generates a new random point value each time it is started. This UMap can also be used on 'init' mode parameters.
5 |
6 | center: (Point) the center of the rectangle within which a random point can be generated.
7 | radius: (Point) x and y radius of the rectangle within which the random point is generated.
8 | value: the output point (can only be changed by the UMap itself)
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | FuncUMapDef( \random_point, { |
16 | unit,
17 | center = #[0.0,0.0],
18 | radius = #[10.0,10.0]|
19 | (center + radius.rand2).asPoint;
20 | })
21 | .category_( 'random' )
22 | .canUseUMapFunc_({ |unit, key, umapdef|
23 | [ PointSpec, WFSPointSpec, WFSRadiusSpec, WFSPlaneSpec, UAdaptSpec ].any({ |class|
24 | unit.getSpec( key ).isMemberOf( class )
25 | });
26 | })
27 | .valueIsMapped_( false )
28 | .numChannels_( 2 )
29 | .setSpec( \value, DisplaySpec( PointSpec(Rect(0,0,1,1)), { |point|
30 | "% @ %".format(point.x, point.y )
31 | }) )
32 | .setDefault( \value, 0.0@0.0 )
33 | .setSpec( \center, WFSPointSpec(200) )
34 | .setSpec( \radius, WFSRadiusSpec(200) );
--------------------------------------------------------------------------------
/WFS/UMapDefs/random_trajectory.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \random_trajectory
3 |
4 | Creates an UMap for generating a random trajectory for modulatable point parameters.
5 |
6 | speed: frequency by which new random positions are generated, in Hz.
7 | center: (Point) the center of the rectangle within which a random path can be generated.
8 | radius: (Point) x and y radius of the rectangle within which the random path is generated.
9 | type: the type of noise used:
10 | 0: step or sample-and-hold noise; hard jumps at each value change
11 | 1: linear interpolated noise
12 | 2: cubic interpolated noise
13 | lag: a smoothing time for changes if 'type' == 0.
14 | seed: Use this to generate a different random path. Paths with the same seed are exactly the same.
15 |
16 | --
17 | this is an UMapDef definition file
18 | part of the WFSCollider Class Library default UMapDefs set
19 | */
20 |
21 | UMapDef( \random_trajectory, { |
22 | speed = 0.1,
23 | center = #[0.0,0.0],
24 | radius = #[10.0,10.0],
25 | type = 2,
26 | lag = 0.1|
27 | var�random, trigger;
28 | URandSeed.ir();
29 | random =�[
30 | LFDNoise0.kr( speed.dup ).lag3( lag ),
31 | LFDNoise1.kr( speed.dup ),
32 | LFDNoise3.kr( speed.dup )
33 | ];
34 | random = LinSelectX.kr( type, random );
35 | random = random.madd( radius, center );
36 | UMapOut.kr( random, false );
37 | })
38 | .category_( 'point_trajectory' )
39 | .canUseUMapFunc_({ |unit, key, umapdef|
40 | unit.getSpec( key ).isKindOf( PointSpec );
41 | })
42 | .canInsert_( false )
43 | .setSpec( \speed, [ 0, 100, 99.squared.log, 0, 0.1 ].asSpec )
44 | .setSpec( \center, WFSPointSpec(200) )
45 | .setSpec( \radius, WFSRadiusSpec(200) )
46 | .setSpec( \type, ListSpec([0,1,2], 0, [\step, \linear, \cubic]) )
47 | .setSpec( \lag, [0,10,\lin,0,0.1].asSpec )
--------------------------------------------------------------------------------
/WFS/UMapDefs/rotate_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \rotate_point
3 |
4 | Creates an UMap intended that rotates and scales an input point.
5 |
6 | point: the point to rotate (can be an UMap)
7 | rotate: the amount of rotation in degrees (-pi - pi)
8 | scale: a scale amount (0.25 - 4)
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the Unit lib default UMapDefs set
13 | */
14 |
15 | UMapDef( \rotate_point, { |point = #[0.0,0.0], rotate = 0.0, scale = 1.0|
16 | point = point.asPoint;
17 | point = point.rotate( rotate.neg ) * [scale,scale];
18 | UMapOut.kr(point.asArray, false);
19 | })
20 | .setSpec( \point, WFSPointSpec(200) )
21 | .setSpec( \rotate, AngleSpec() )
22 | .setSpec( \scale, [0.25,4,\exp,0,1].asSpec )
23 | .category_( 'point_utility' )
24 | .canUseUMapFunc_({ |unit, key, umapdef|
25 | unit.getSpec( key ).isKindOf( PointSpec );
26 | });
27 |
--------------------------------------------------------------------------------
/WFS/UMapDefs/sample_and_hold_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \sample_and_hold_point
3 |
4 | This UMap implements sample-and-hold process for points. Every time a trigger is received the output point becomes the input point of that moment.
5 |
6 | point: the point or point UMap to sample
7 | trigger: the trigger
8 | time: a linear lag time to move to the new point
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \sample_and_hold_point, {
16 | var point, trigger, output;
17 | point = \point.kr([0.0,0.0]);
18 | trigger = \trigger.tr;
19 | output = Select.kr( Peak.kr( trigger), [ DC.kr( point ), Latch.kr( point, trigger ) ]);
20 | output = output.varlag( \time.kr(0.0) );
21 | UMapOut.kr( output, false );
22 | })
23 | .canUseUMapFunc_({ |unit, key, umapdef|
24 | unit.getSpec( key ).isKindOf( PointSpec );
25 | })
26 | .setSpec( \point, WFSPointSpec(200,0.1) )
27 | .setSpec( \trigger, TriggerSpec() )
28 | .category_( 'point_utility' )
--------------------------------------------------------------------------------
/WFS/UMapDefs/scale_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \scale_point
3 |
4 | Creates an UMap for scaling and moving a point. The point can also be UMaps.
5 |
6 | point: the first point
7 | scale: a multiplier for x/y
8 | move: a point to add to the point
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \scale_point, { |
16 | point = #[0.0, 0.0],
17 | scale = #[1.0,1.0],
18 | move = #[0.0,0.0]|
19 | UMapOut.kr( (point * scale) + move, false );
20 | })
21 | .category_( 'point_utility' )
22 | .canUseUMapFunc_({ |unit, key, umapdef|
23 | unit.getSpec( key ).isKindOf( PointSpec );
24 | })
25 | .setSpec( \point, WFSPointSpec(200) )
26 | .setSpec( \scale, WFSPointSpec(200) )
27 | .setSpec( \move, WFSPointSpec(200) );
--------------------------------------------------------------------------------
/WFS/UMapDefs/select_8_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \select_8_point
3 |
4 | Creates an UMap that can select one from 8 points.
5 |
6 | index: the index of the point (0-7)
7 | interpolation: interpolation type (0:step, 1:linear) // cubic: todo
8 | point0 - point7: the values of the steps (can be UMaps)
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the Unit lib default UMapDefs set
13 | */
14 |
15 | UMapDef( \select_8_point, {
16 | var points, interpolation;
17 | var index, sig;
18 | index = \index.kr(0);
19 | interpolation = \interpolation.kr(1.0);
20 | points = 8.collect({ |i|
21 | ("point"++i).asSymbol.kr([0.0,0.0]);
22 | });
23 | sig = Select.kr(
24 | interpolation,
25 | [
26 | Select.kr( index, points ),
27 | LinSelectX.kr( index, points )
28 | ]
29 | );
30 | UMapOut.kr( sig, false );
31 | }).category_( \point_utility )
32 | .canUseUMapFunc_({ |unit, key, umapdef|
33 | unit.getSpec( key ).isKindOf( PointSpec );
34 | })
35 | .setSpec( \interpolation, BoolSpec(true) )
36 | .setSpec( \index, [0,7].asSpec )
37 | .setSpec( \point0, WFSPointSpec(200, 0.1) )
38 | .setSpec( \point1, WFSPointSpec(200, 0.1) )
39 | .setSpec( \point2, WFSPointSpec(200, 0.1) )
40 | .setSpec( \point3, WFSPointSpec(200, 0.1) )
41 | .setSpec( \point4, WFSPointSpec(200, 0.1) )
42 | .setSpec( \point5, WFSPointSpec(200, 0.1) )
43 | .setSpec( \point6, WFSPointSpec(200, 0.1) )
44 | .setSpec( \point7, WFSPointSpec(200, 0.1) )
--------------------------------------------------------------------------------
/WFS/UMapDefs/shared_point_in.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \shared_point_in
3 |
4 | ** this UMapDef should be used in conjunction with 'shared_point_out' **
5 |
6 | The shared_in_point UMapDef can receive point information from UMaps used earlier in the chain. This is useful when multiple units or unit parameters need to use the same point information, or derrive things from it. The shared_in_point would always need to come after a 'shared_point_out' in the order of the chain; it recieves the point data from a bus. To send the data in an other unit or parameter use the 'shared_point_out' UMapDef, and make sure the 'id' setting is the same on both. There can be multiple 'shared_point_in' UMaps with the same 'id' in one chain, which would all receive data from the same 'shared_out_point'. All this will only work _within_ a single chain.
7 |
8 | id: the id (0-99) by which the point can be retreived from 'shared_out_point'
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \shared_point_in, {
16 | var sig;
17 | sig = USharedPointIn.kr( \id );
18 | UMapOut.kr(sig, false);
19 | })
20 | .setSpec( \id, SharedPointIDSpec( 0 ) )
21 | .category_( 'shared_io' )
22 | .canUseUMapFunc_({ |unit, key, umapdef|
23 | unit.getSpec( key ).isKindOf( PointSpec );
24 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/shared_point_out.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \shared_point_out
3 |
4 | ** this UMapDef should be used in conjunction with 'shared_point_in' **
5 |
6 | The shared_point_out UMapDef creates an UMap that is able to share point information with other UMaps used further in the chain. This is useful when multiple units or unit parameters need to use the same point information, or derrive things from it. The shared_point_out would always need to come first in the order of the chain; it sends the point data to a bus. To retreive the data in an other unit or parameter use the 'shared_in_point' UMapDef, and make sure the 'id' setting is the same on both. This will only work _within_ a single chain.
7 |
8 | point: the point to be shared (can be an UMap)
9 | id: the id (0-99) by which the point can be retreived by 'shared_point_in'
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 | UMapDef( \shared_point_out, { |point = #[0.0, 0.0], id = 0|
17 | id = id * 2;
18 | ReplaceOut.kr(id + 1200, point[0]);
19 | ReplaceOut.kr(id + 1201, point[1]);
20 | UMapOut.kr(point, false);
21 | })
22 | .setSpec( \point, WFSPointSpec(200, 0.1) )
23 | .setSpec( \id, SharedPointIDSpec( 0 ) )
24 | .category_( 'shared_io' )
25 | .canUseUMapFunc_({ |unit, key, umapdef|
26 | unit.getSpec( key ).isKindOf( PointSpec );
27 | });
--------------------------------------------------------------------------------
/WFS/UMapDefs/slew_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \slew_point
3 |
4 | Creates an UMap for applying a speed limit to point input.
5 |
6 | point: the point to lag
7 | maxSpeed: maximum speed in m/s
8 |
9 | --
10 | this is an UMapDef definition file
11 | part of the WFSCollider Class Library default UMapDefs set
12 | */
13 |
14 | UMapDef( \slew_point, { |
15 | point = #[0.0, 0.0],
16 | maxSpeed = 1
17 | |
18 | point = Slew.kr( point, maxSpeed, maxSpeed );
19 | UMapOut.kr(point, false);
20 | })
21 | .setSpec( \point, WFSPointSpec(200, 0.1) )
22 | .setSpec( \maxSpeed, [0,344,8].asSpec )
23 | .category_( 'point_filter' )
24 | .canUseUMapFunc_({ |unit, key, umapdef|
25 | unit.getSpec( key ).isKindOf( PointSpec );
26 | })
--------------------------------------------------------------------------------
/WFS/UMapDefs/trajectory.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \trajectory
3 |
4 | A player for 2D spatial trajectories. The WFSPathGUI; an editor for trajectories, can be called up via the [edit] button in the UChain window. This umap is intended for use on units with PointSpec or WFSPointSpec based args.
5 |
6 | trajectory: a WFSPathBuffer object. This object creates and points to a buffer with the data of the trajectory. This buffer is either filled with data sent directly, or data read from a .wfspath file (generated via the [write data] button in the GUI). For larger trajectories (50+ breakpoints) data from file can be more reliable than sending via network, but for the vast majority it is not needed to use the [write data] option.
7 | trigger: a trigger to (re)start the trajectory
8 | addPoint: a point (or point UMap) can be added to the trajectory position, effectively moving the trajectory as a whole.
9 |
10 | --
11 | this is an UMapDef definition file
12 | part of the WFSCollider Class Library default UMapDefs set
13 | */
14 |
15 | UMapDef( \trajectory, {
16 | var sig;
17 | sig = WFSPathBufferPlayer.kr( \trajectory, \trigger );
18 | sig = sig + \addPoint.kr([0,0]);
19 | UMapOut.kr( sig, false );
20 | }, [
21 | [ \trajectory, nil, WFSPathSpec() ],
22 | [ \trigger, 1, TriggerSpec() ],
23 | [ \addPoint, 0@0, WFSPointSpec(200, 0.1@0.1) ]
24 | ])
25 | .category_( \point_trajectory )
26 | .canInsert_( false )
27 | .canUseUMapFunc_({ |unit, key, umapdef|
28 | unit.getSpec( key ).isKindOf( PointSpec );
29 | });
--------------------------------------------------------------------------------
/WFS/UNodeIDAllocator.sc:
--------------------------------------------------------------------------------
1 | UNodeIDAllocator {
2 | // a node allocator excluding any nodeID above 2**24
3 | // because those are incompatible with 32bits floats
4 | // and therefore cannot be used for pausing/unpausing
5 | // nodes from within synths.
6 |
7 | classvar <>maxUsers = 2;
8 | var = maxUsers) { "NodeIDAllocator maxUsers (%) exceeded".format( maxUsers ).error; ^nil };
13 | ^super.newCopyArgs(user, initTemp).reset
14 | }
15 |
16 | idOffset { ^(wrapper + 1) * user }
17 |
18 | powerOfTwo { ^25 - maxUsers }
19 | getNumIDs { ^(2 ** this.powerOfTwo).asInteger }
20 |
21 | numIDs { ^wrapper + 1 }
22 |
23 | reset {
24 | wrapper = this.getNumIDs - 1;
25 | mask = user << this.powerOfTwo;
26 | temp = initTemp;
27 | perm = 2;
28 | permFreed = IdentitySet.new;
29 | }
30 | alloc {
31 | var x;
32 | x = temp;
33 | temp = (x + 1).wrap(initTemp, wrapper);
34 | //"allocated: %\n".postf( x | mask );
35 | ^x | mask
36 | }
37 | allocPerm {
38 | var x;
39 | if(permFreed.size > 0) {
40 | x = permFreed.minItem;
41 | permFreed.remove(x);
42 | } {
43 | x = perm;
44 | perm = (x + 1).min(initTemp - 1);
45 | }
46 | ^x | mask
47 | }
48 | freePerm { |id|
49 | // should not add a temp node id to the freed-permanent collection
50 | id = id bitAnd: wrapper;
51 | if(id < initTemp) { permFreed.add(id) }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/WFS/UPanCenter/USpeakerConf.sc:
--------------------------------------------------------------------------------
1 | USpeakerConf : WFSPointGroup {
2 |
3 | classvar <>default;
4 | classvar <>current;
5 |
6 | var listener;
7 |
8 | *new { |positions, listener|
9 | ^super.newCopyArgs( positions, listener ).init;
10 | }
11 |
12 | init {
13 | this.changed( \init );
14 | }
15 |
16 | listener_ { |point|
17 | listener = point.asPoint;
18 | this.changed( \listener );
19 | }
20 |
21 | listener {
22 | if( listener.isNil ) { this.listener = 0@0; };
23 | ^listener
24 | }
25 |
26 | }
27 |
28 | USpeakerConfView : WFSMixedView {
29 |
30 | var <>type = \speaker;
31 |
32 | points { ^(object !? _.positions) ? [] }
33 |
34 | points_ { |points|
35 | points = points.asUSpeakerConf;
36 | if( this.object.isNil ) {
37 | this.object = points;
38 | } {
39 | if( canChangeAmount ) {
40 | this.object.positions = points.positions;
41 | } {
42 | this.object.positions = this.object.positions.collect({ |item, i|
43 | points[i] ?? { object[i] };
44 | });
45 | };
46 | };
47 | }
48 |
49 | center { ^this.object.listener }
50 | }
51 |
52 | USpeakerConfTransformerView : WFSPointGroupTransformerView {
53 |
54 | revertObject {
55 | object.positions = objectCopy.positions.deepCopy;
56 | }
57 |
58 | makeObjectCopy {
59 | objectCopy = object.deepCopy;
60 | }
61 |
62 | makeEditFuncs { |editDefs|
63 |
64 | WFSPathGeneratorDef.loadOnceFromDefaultDirectory;
65 |
66 | ^(editDefs ?? { [ \circleSize, \polygon, \align, \move, \scale, \rotate, \sort ] }) .asCollection
67 | .collect(_.asWFSPathTransformer)
68 | .select(_.notNil);
69 | }
70 |
71 |
72 | }
73 |
74 | USpeakerConfEditView : WFSPointGroupEditView {
75 | viewClass { ^USpeakerConfView }
76 | }
77 |
78 | USpeakerConfGUI : WFSPointGroupGUI {
79 | editViewClass { ^USpeakerConfEditView }
80 | transformerViewClass { ^USpeakerConfTransformerView }
81 | }
82 |
83 | + Object {
84 | isUSpeakerConf { ^false }
85 | }
86 |
87 | + WFSPath2 {
88 | asUSpeakerConf {
89 | ^USpeakerConf( this.positions.collect(_.asPoint) );
90 | }
91 | }
92 |
93 | + Collection {
94 | asUSpeakerConf {
95 | ^USpeakerConf( this.collectAs(_.asPoint, Array) );
96 | }
97 | }
98 |
99 | + Symbol {
100 | asUSpeakerConf { |size = 20|
101 | ^USpeakerConf.generate( size, this );
102 | }
103 | }
104 |
105 | + Nil {
106 | asUSpeakerConf {
107 | ^USpeakerConf( { |i| Polar( 8, i.linlin(0,15,0,2pi) ).asPoint } ! 15 );
108 | }
109 | }
110 |
111 | + WFSPath_Old {
112 | asWFSPointGroup {
113 | ^WFSPointGroup( this.positions.collect(_.asPoint) );
114 | }
115 | }
--------------------------------------------------------------------------------
/WFS/UScore-openWFS.sc:
--------------------------------------------------------------------------------
1 | /*
2 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
3 | The Game Of Life Foundation. http://gameoflife.nl
4 | Copyright 2006-2011 Wouter Snoei.
5 |
6 | GameOfLife WFSCollider software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | GameOfLife WFSCollider is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with GameOfLife WFSCollider. If not, see .
18 | */
19 |
20 | + UScore{
21 |
22 | *openWFS{ |path, action|
23 | var score;
24 | var f = { |path,action|
25 |
26 | if( File(path,"r").readAllString[..8] == "") {
27 | score = WFSScore.readWFSFile(path).asUEvent;
28 | action.value(score);
29 | score
30 | } {
31 | score = this.readTextArchive( path );
32 | action.value(score);
33 | score
34 | }
35 |
36 | };
37 | if( path.isNil ) {
38 | Dialog.getPaths( { |paths|
39 | f.(paths[0],action);
40 | });
41 | } {
42 | path = path.standardizePath;
43 | f.(path,action)
44 | };
45 | }
46 | }
--------------------------------------------------------------------------------
/WFS/USharedPointIO.sc:
--------------------------------------------------------------------------------
1 | USharedPointIn : USharedValueIn {
2 |
3 | classvar <>busOffset = 1200;
4 |
5 | *spec { |default| ^SharedPointIDSpec( default ) }
6 |
7 | *kr { |id, default = 0|
8 | ^In.kr( (this.makeInput( id, default ) * 2) + this.busOffset + [0,1] );
9 | }
10 | }
11 |
12 | USharedPointOut : USharedPointIn {
13 |
14 | *kr { |id, channelsArray, default = 0|
15 | id = this.makeInput( id, default ) * 2;
16 | channelsArray = channelsArray.asArray;
17 | ^[
18 | ReplaceOut.kr( id + this.busOffset, channelsArray[0] ),
19 | ReplaceOut.kr( id + this.busOffset + 1, channelsArray[1] )
20 | ]
21 | }
22 | }
--------------------------------------------------------------------------------
/WFS/UnitDefs/envir_point_set.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \envir_point_set
3 |
4 | ** this Udef can be used in conjunction with 'envir_point_get' and 'p_envir_point_get' UMaps **
5 |
6 | The 'envir_point_set' Udef creates a unit that is able to globally share a value with other units used further in the chain, or in other chains. To use the value within the same chain, an 'envir_point_set' unit should always be first in the order of the chain. It makes the value available as an Environment value, which is globally accessible. To retreive the value in an other unit use the 'p_envir_point_get' or 'envir_point_get' UMapDef, and make sure the 'key' setting is the same on both. The value is can also be accessed via SuperCollider code, by adding a '~' in front of the name. The value can be set in 5 different formats: value (0-1), freq (2-20000), amp (0-1, curved for amplitude use), boolean (true/false) and time (0-inf). The 'p_envir_point_get' UMapDef will automatically map the value to the range of the parameter it is connected to, which means it is possible to use for example the 'freq' value of this unit to influence the 'amp' value of another unit. The 'envir_point_set' unit itself does not output any sound, it only makes the value available.
7 |
8 | point: the point to share (can be UMap, but only from a function, control, midi or pattern category)
9 | key: the name of the variable (default: 'a')
10 |
11 | --
12 | this is an Udef definition file
13 | part of the WFSCollider Class Library default UDefs set
14 | */
15 |
16 | var defs, makeDef, multiDefault;
17 |
18 | multiDefault = WFSPointGroup.generate( 8, \circle ).positions;
19 |
20 | makeDef = { |name, argname, default, spec|
21 | FreeUdef( name, [
22 | [ argname, default, spec, false, \init ],
23 | [ \key, \p, EnvirSpec() ],
24 | ], addToAll: false )
25 | .apxCPU_( 0 )
26 | .prepareFunc_({ |server, unit, action, startPos = 0|
27 | var value;
28 | value = unit.get( argname );
29 | unit.get( \key ).asSymbol.uEnvirPut( value.value, WFSPointSpec(200) );
30 | if( value.isKindOf( UMap ) ) {
31 | value.start
32 | };
33 | action.value;
34 | })
35 | .createsSynth_( false )
36 | .setSynthFunc_({ |unit ...keyValuePairs|
37 | unit.get( \key ).asSymbol.uEnvirPut( unit.get( argname ).value, WFSPointSpec(200) );
38 | })
39 | .category_( 'envir' )
40 | };
41 |
42 | defs = [
43 | makeDef.value( \single, \point, 0@0, WFSPointSpec(200) ),
44 | makeDef.value( \array, \points, multiDefault, WFSMultiPointSpec(200, default: multiDefault ) ),
45 | ];
46 |
47 | MultiUdef( \envir_point_set, defs, \envir, \type, false )
48 | .apxCPU_( 0 );
49 |
--------------------------------------------------------------------------------
/WFS/UnitDefs/furseDistanceFilter.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \furseDistanceFilter
3 |
4 | ** if a furseDistanceFilter is used in combination with a wfsDynamicPoint or wfsStaticPoint in a chain, the next time the score is opened it will be removed and replaced by a 'distanceFilter' setting in on the panner unit **
5 |
6 | The furseDistanceFilter is a filter that applies distance filtering according to a formula by Richard W. Furse (http://www.muse.demon.co.uk/vspace/model.html):
7 |
8 | cutoff = 100000 / distance
9 |
10 | where cutoff is Hz and distance is in metres.
11 |
12 | point: a Point from which the distance to the center of the room (0,0) is determined
13 | amount: strength of the effect. A cubed multiplier for the distance. 0 means no filtering, 1 means normal, 2 means the distance in the formula is multiplied by 8 (2**3).
14 |
15 | --
16 | this is an Udef definition file
17 | part of the WFSCollider Class Library default Udefs set
18 | */
19 |
20 | Udef( \furseDistanceFilter, {
21 | var sig, point = (0@0), freq;
22 | point = \point.kr( point.asArray ).asPoint;
23 | sig = UIn.ar(0);
24 | freq = (100000 / ( point.rho * \amount.kr(1).cubed )).clip(0,100000);
25 | sig = OnePole.ar( sig, ( -2pi * (freq / SampleRate.ir) ).exp );
26 | UOut.ar( 0, sig );
27 | }).category_( \filter )
28 | .prepareArgsFunc_({ |argPairs|
29 | var point;
30 | if( argPairs.notNil) {
31 | if( argPairs.pairsAt( \pointFromBus ) == true ) {
32 | if( argPairs.includes( \u_i_kr_0_bus ) or: {
33 | argPairs.includes( \u_i_kr_1_bus )
34 | } ) {
35 | argPairs = [ \point, [ \map_control_point, [
36 | \bus_x, argPairs.pairsAt( \u_i_kr_0_bus ) ? 0,
37 | \bus_y, argPairs.pairsAt( \u_i_kr_1_bus ) ? 1
38 | ]
39 | ], \pointFromBus, false ] ++ argPairs;
40 | } {
41 | argPairs = [ \point, \map_control_point, \pointFromBus, false ] ++ argPairs;
42 | };
43 | };
44 | };
45 | })
46 | .uchainInitFunc_({ |unit, chain|
47 | var removeMe = false;
48 |
49 | chain.units.select({ |item|
50 | ([ \wfsDynamicPoint, \wfsStaticPoint ].includes( item.defName )) && {
51 | if( item.point.isUMap && unit.point.isUMap ) {
52 | (item.point.defName == unit.point.defName) && {
53 | item.point.args == unit.point.args;
54 | };
55 | } {
56 | item.point == unit.point;
57 | };
58 | } && {
59 | unit.getAudioOut(0) == item.getAudioIn(0)
60 | }
61 | }).do({ |item|
62 | item.distanceFilter = unit.amount;
63 | removeMe = true;
64 | });
65 |
66 | if( removeMe ) {
67 | chain.units.remove( unit );
68 | chain.units = chain.units; // update GUI / re-init
69 | };
70 | })
71 | .setSpec( \amount, [0,2,\lin,0,1].asSpec )
72 | .setSpec( \point, WFSPointSpec(200, 0.1) );
--------------------------------------------------------------------------------
/WFS/UnitDefs/shared_point.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \shared_point
3 |
4 | ** this Udef should be used in conjunction with 'shared_point_in' UMap **
5 |
6 | The shared_point Udef creates an unit that is able to share point information with other units used further in the chain. This is useful when multiple units or unit parameters need to use the same point information, or derrive things from it. The shared_point would always need to come first in the order of the chain; it sends the point data to a bus. To retreive the data in another unit use the 'shared_in_point' UMapDef, and make sure the 'id' setting is the same on both. This will only work _within_ a single chain.
7 |
8 | point: the point to be shared (can be an UMap)
9 | id: the id (0-99) by which the point can be retreived by 'shared_point_in'
10 |
11 | --
12 | this is an UMapDef definition file
13 | part of the WFSCollider Class Library default UMapDefs set
14 | */
15 |
16 | Udef( \shared_point, { |point = #[0.0, 0.0]|
17 | UEnv.kr( extraSilence: 0.2, useGlobalGain: 0 );
18 | USharedPointOut.kr( \id, point );
19 | })
20 | .setSpec( \point, WFSPointSpec(200, 0.1) )
21 | .category_( 'shared_io' );
--------------------------------------------------------------------------------
/WFS/UnitDefs/simpleReverb.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \simpleReverb
3 |
4 | ** simpleReverb is deprecated, please use FreeVerb and UMaps instead **
5 |
6 | This reverb has to be used together with a wfs_control, like wfsPoint. The control busses of wfsPoint have to be connected to the control busses of simpleReverb. To connect the busses, click on i/o in the toolbar.
7 |
8 | The distance of the point from the center of the speaker arrays is used to calculate the damping of the reverb. The maximum damping occurs at a distance of 8 metres. The distance is static and stays the same after the reverb is started.
9 |
10 | To mix the reverb with the original signal, another wfs-panner is needed, like wfsStaticPoint. This Udef needs to be placed directly behind the source that goes into simpleReverb.
11 |
12 | time: reverb length.
13 | room: room size.
14 | amp: level of the reverberated signal (wet only).
15 |
16 | --
17 | this is an Udef definition file
18 | part of the WFSCollider Class Library default Udefs set
19 | */
20 |
21 | Udef( \simpleReverb, { |point = #[0,0], time = 0.1, room = 0.5, amp = 0.2|
22 | var in, rev, dist;
23 | in = UIn.ar( 0, 1 );
24 | dist = point.asPoint.rho;
25 | rev = FreeVerb.ar( in, 1, room, dist.linlin(0.0,8.0,0.0,1.0) ) * amp * dist.linlin(0.0,8.0,0.0,1.0);
26 | UOut.ar( 0, rev )
27 | } )
28 | .category_( \private )
29 | .prepareArgsFunc_({ |argPairs|
30 | argPairs = argPairs.asCollection;
31 | if( argPairs.includes( \point ).not ) {
32 | if( argPairs.includes( \u_i_kr_0_bus ) or: { argPairs.includes( \u_i_kr_1_bus ) } ) { argPairs = [ \point, [ \map_control_point, [
33 | \bus_x, argPairs.pairsAt( \u_i_kr_0_bus ) ? 0,
34 | \bus_y, argPairs.pairsAt( \u_i_kr_1_bus ) ? 1
35 | ]
36 | ],
37 | ] ++ argPairs;
38 | } {
39 | argPairs = [ \point, \map_control_point ] ++ argPairs;
40 | };
41 | };
42 | argPairs;
43 | })
44 | .setSpec( \point, WFSPointSpec(200,0.1) )
45 | .setSpec( \room, [ 0, 1, \lin, 0, 0.5 ] )
46 | .setSpec( \amp, [0,1,\lin, 0.2], \normal )
47 |
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsDynamicIndex.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsDynamicIndex
3 |
4 | This udef can send sound to an individual speaker on the WFS system. The index of the speaker can be changed in realtime (dynamic).
5 |
6 | index: the number of the speaker, starting at 0.
7 | gain: the output level (dB).
8 |
9 | --
10 | this is an Udef definition file
11 | part of the WFSCollider Class Library default Udefs set
12 | */
13 |
14 | (
15 | var def;
16 | def = FreeUdef( \wfsDynamicIndex, [
17 | [ \index: 0, PositiveIntegerSpec() ],
18 | [ \gain: -6, [ -96, 0, \db, 1, -6].asSpec ],
19 | ] )
20 | .category_( \private )
21 | .synthDef_(
22 | SynthDef( "wfsi_id", {
23 | var input, env, maxIndex;
24 | var gain = -10.dbamp;
25 | var index = 0, indexFromBus = 0;
26 |
27 | index = \index.kr(index);
28 |
29 | index = index - \startIndex.kr(0);
30 | gain = gain * \wfs_gain.ir(0).dbamp;
31 | gain = gain * \gain.kr(-6).dbamp;
32 | maxIndex = NumOutputBuses.ir; // only output to hardware outs
33 |
34 | gain = gain * InRange.kr(index, 0, maxIndex); // mute when out of range
35 |
36 | input = UGlobalEQ.ar( UIn.ar(0, 1) ) * gain * UEnv.kr;
37 |
38 | Out.ar( index.clip(0, maxIndex), input );
39 | })
40 | )
41 | .addSynthDefControls
42 | .shouldPlayOnFunc_({ |unit, target|
43 | WFSSpeakerConf.includesServer( target.asTarget.server );
44 | })
45 | .createSynthFunc_({ |unit, target, startPos = 0|
46 | var startIndex;
47 | startIndex = WFSSpeakerConf.default.firstSpeakerIndexOf( target.asTarget.server );
48 | Synth( "wfsi_id", [
49 | \startIndex, startIndex - WFSSpeakerConf.getOutputBusStartOffset( target ),
50 | \wfs_gain, WFSSpeakerConf.default.gain
51 | ] ++ unit.getArgsFor( target, startPos ),
52 | target, \addToTail );
53 | })
54 | .setControlInName( 0, 'index' );
55 |
56 | def.removeArgSpec( \startIndex ); // this is set by createSynthFunc
57 | def.removeArgSpec( \wfs_gain ); // this is set by createSynthFunc
58 |
59 | def.uchainInitFunc_({ |unit, chain|
60 | if( unit.index.isUMap.not or: { unit.index.def.allowedModes.includes( \init ); } ) {
61 | unit.index = [ \lag, [ \value, unit.index, \time, 0 ] ]; // force dynamic
62 | };
63 | unit.def = \wfsIndex.asUdef;
64 | });
65 |
66 | def
67 | )
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsMasterIn.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsMasterIn
3 |
4 | Input audio from a hardware input of the master audio interface of the system (if there is one).
5 |
6 | Using this Udef in a UChain will cause the whole UChain to be played on the master computer instead of the servers.
7 |
8 | bus: number of the hardware input bus (starting at 0).
9 | numChannels: number of channels (*)
10 |
11 | (*) only the following numbers of channels are allowed:
12 | 1,2,3,4,5,6,7,8,10,12,16,24,32
13 |
14 | --
15 | this is an Udef definition file
16 | part of the WFSCollider Class Library default Udefs set
17 | */
18 |
19 | MultiChannelUdef( \wfsMasterIn, { |bus = 0|
20 | var input;
21 | input = ((..Udef.numChannels - 1) + bus).collect({ |item| SoundIn.ar( item ) });
22 | input = input.collect({ |input|
23 | input * if( bus > (NumInputBuses.ir - 1), 0, 1 );
24 | });
25 | UOut.ar( 0, input );
26 | } ).setSpec( \bus, PositiveIntegerSpec( 0 ) )
27 | .category_( \private )
28 | .uchainInitFunc_({ |unit, chain|
29 | // this function replaces the wfsPoint unit in the chain
30 | // by a \shared_point, and any of \map_control_point UMaps
31 | // further in the chain by corresponding \shared_point_in
32 | unit.def = \soundIn.asUdef;
33 | })
34 | .shouldPlayOnFunc_({ |unit, target|
35 | target.asTarget.server == WFSServers.default.m;
36 | });
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsMasterOut.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsMasterOut
3 |
4 | Output audio from the master audio interface of the system (if there is one).
5 |
6 | Using this Udef in a UChain will cause the whole UChain to be played on the master computer instead of the servers.
7 |
8 | On the Game of Life WFS system it can be used either to send audio digitally from the master computer to the servers (for which there are 8 buses available � i.e. one ADAT cable), or to the analog outputs of the master audio interface (for example to send audio signals in sync with the WFS system to other speakers or headphones).
9 |
10 | bus: number of a hardware output (starting at 0)
11 | toServers: if true (default), the output is to the digital inputs of the servers. If not selected, it is sent to analog outputs.
12 | numChannels: number of channels (1-8)
13 |
14 | --
15 | this is an Udef definition file
16 | part of the WFSCollider Class Library default Udefs set
17 | */
18 |
19 | MultiChannelUdef( \wfsMasterOut, { |bus = 0, toServers = 1, u_busOffset = 14|
20 | var minBus, maxBus, useGlobalGain;
21 | minBus = (u_busOffset * toServers);
22 | maxBus = if( toServers, NumOutputBuses.ir - 1, u_busOffset - 1 );
23 | bus = bus + minBus;
24 | useGlobalGain = 1 - toServers;
25 | bus = bus * InRange.kr( bus, minBus, maxBus );
26 |
27 | Out.ar( bus, UIn.ar( 0, Udef.numChannels ) * UEnv.kr( useGlobalGain: useGlobalGain ) );
28 | }, channels: (1..8))
29 | .category_( \private )
30 | .setSpec( \u_busOffset, PositiveIntegerSpec( 14 ) )
31 | .setSpec( \bus, PositiveIntegerSpec( 0 ) )
32 | .setSpec( \toServers, BoolSpec( true ) )
33 | .shouldPlayOnFunc_({ |unit, target|
34 | target.asTarget.server == WFSServers.default.m;
35 | });
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsPathPlayer.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsPathPlayer
3 |
4 | ** wfsPathPlayer is deprecated and will be removed at some point. Please use the \trajectory UMapDef instead. This Udef has a built-in function which makes it replace itself by a \trajectory UMap which is automaticaly inserted at the correct places, when it is found in a saved .uscore file or created via code **
5 |
6 | A player for spatial trajectories. The WFSPathGUI can be called up via the [edit] button in the UChain window.
7 |
8 | This signal can be used by the wfsDynamicPoint and wfsDynamicPlane udefs, by checking their 'pointFromBus' argument.
9 |
10 | wfsPath: a WFSPathBuffer object. This object creates and points to a buffer with the data of the trajectory. This buffer is either filled with data sent directly, or data read from a .wfspath file (generated via the [write data] button in the GUI). Data from file is usually more reliable than sending via network.
11 |
12 | --
13 | this is an Udef definition file
14 | part of the WFSCollider Class Library default Udefs set
15 | */
16 |
17 | Udef( \wfsPathPlayer, {
18 | var sig;
19 | sig = WFSPathBufferPlayer.kr( \wfsPath );
20 | UMixOut.kr( 0, sig );
21 | }, [ [ \wfsPath, nil, WFSPathSpec() ] ] )
22 | .category_( 'private' )
23 | .uchainInitFunc_({ |unit, chain|
24 | // this function removes or replaces the wfsPathPlayer unit in the chain
25 | // by the currently used UMaps at load time.
26 | var outputs, removeMe = false;
27 | var umaps, trajectory;
28 | var newUMap, mixOut;
29 |
30 | outputs = unit.controlOuts.collect({ |item|
31 | unit.getControlOut( item );
32 | }).asInteger;
33 |
34 | mixOut = unit.controlOuts.collect({ |item|
35 | unit.getControlMixOutLevel( item );
36 | });
37 |
38 | umaps = chain.units.collect({ |unit|
39 | (unit.getAllUMaps ? []).select({ |umap|
40 | (umap.defName === \map_control_point) && {
41 | [umap.bus_x, umap.bus_y].asInteger == outputs;
42 | }
43 | })
44 | }).flatten(1);
45 |
46 | if( umaps.size < 2 ) {
47 | // if only used once, directly insert at that spot
48 | umaps.do({ |umap|
49 | umap.def = \trajectory.asUdef(UMapDef);
50 | umap.trajectory = unit.wfsPath;
51 | newUMap = umap;
52 | removeMe = true;
53 | });
54 | } {
55 | // if used multiple times, use a \shared_point
56 | umaps.do({ |umap|
57 | umap.def = \shared_point_in.asUdef(UMapDef);
58 | umap.id = outputs[0] / 2;
59 | });
60 | };
61 |
62 | if( removeMe ) {
63 | chain.units.remove( unit );
64 | chain.units = chain.units; // update GUI / re-init
65 | } {
66 | trajectory = unit.wfsPath; // in any case, replace by a \shared_point
67 | unit.def = \shared_point.asUdef;
68 | unit.point = [ \trajectory, [ \trajectory, trajectory ] ];
69 | unit.id = outputs[0] / 2;
70 | newUMap = unit.point;
71 | };
72 |
73 | case { mixOut == [1,1] } {
74 | newUMap.addPoint = [ \map_control_point, [ \bus_x, outputs[0], \bus_y, outputs[1] ] ];
75 | } { mixOut.any(_ != 0) } {
76 | newUMap.addPoint = [ \scale_point, [
77 | \scale, mixOut.asPoint,
78 | \point, [ \map_control_point, [ \bus_x, outputs[0], \bus_y, outputs[1] ] ]
79 | ] ];
80 | };
81 | })
82 | .setControlOutName( [0,1], ['x', 'y'] );
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsPoint.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsPoint
3 |
4 | ** deprecated (will be removed soon), please use 'shared_point' instead. When loaded in a score file or created via code this Udef will auto-replace itself by a shared_point, and automatically insert shared_point_in UMaps at the appropriate places **
5 |
6 | a Udef generating a single spatial position. Use this if you want to change your point live, and feed the location to multiple units in your chain (such as \furseDistanceFilter or reverbs).
7 |
8 | This signal can be used by the wfsDynamicPoint and wfsDynamicPlane udefs, by checking their 'pointFromBus' argument.
9 |
10 | point: a Point object, specifying the position produced by this udef
11 | lag: a smoothing time for changes in the position. This uses a second-order filter, which may cause slight oscillations at beginnings and endings of movements. Changing the lag time during playback may cause audible artifacts.
12 |
13 | --
14 | this is an Udef definition file
15 | part of the WFSCollider Class Library default Udefs set
16 | */
17 |
18 | Udef(\wfsPoint,
19 | { |point = #[0,0], lag = 0|
20 | point = LPFLag.kr( point, lag );
21 | UOut.kr(0, point)
22 | }, [
23 | [ \point: 0@0, WFSPointSpec( 200, 0.1 ) ],
24 | [ \lag: 0, [ 0, 1, \lin, 0, 0].asSpec ]
25 | ]
26 | ).category_( 'private' )
27 | .uchainInitFunc_({ |unit, chain|
28 | // this function replaces the wfsPoint unit in the chain
29 | // by a \shared_point, and any of \map_control_point UMaps
30 | // further in the chain by corresponding \shared_point_in
31 | var outputs, removeMe = false;
32 | var umaps, point;
33 |
34 | outputs = unit.controlOuts.collect({ |item|
35 | unit.getControlOut( item );
36 | }).asInteger;
37 |
38 | chain.units.collect({ |unit|
39 | (unit.getAllUMaps ? []).select({ |umap|
40 | (umap.defName === \map_control_point) && {
41 | [umap.bus_x, umap.bus_y].asInteger == outputs;
42 | }
43 | })
44 | }).flatten(1).do({ |umap|
45 | umap.def = \shared_point_in.asUdef(UMapDef);
46 | umap.id = outputs[0] / 2;
47 | });
48 |
49 | unit.def = \shared_point.asUdef;
50 | unit.id = outputs[0] / 2;
51 | })
52 | .setControlOutName( [0,1], ['x', 'y'] );
53 |
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsServerIn.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsServerIn
3 |
4 | Input audio sent digitally from the master computer on the server.
5 |
6 | Using this Udef in your UChain will make the UChain play only on the servers. It is meant to use together with another UChain that holds a wfsMasterOut. Together, these can make a bridge between the master computer and the servers, typically needed for feeding live audio into the system and distributing it over the servers. On the Game of Life WFS system there are 8 buses available for this.
7 |
8 | bus: number of the hardware input bus (0-7).
9 | numChannels: number of channels (1-8)
10 |
11 | --
12 | this is an Udef definition file
13 | part of the WFSCollider Class Library default Udefs set
14 | */
15 |
16 |
17 | var def, maxInput = 8;
18 | if( WFSSpeakerConf.serverGroups[0].notNil ) {
19 | maxInput = WFSSpeakerConf.serverGroups[0].choose.options.numInputBusChannels;
20 | };
21 | def = MultiChannelUdef( \wfsServerIn, { |bus = 0| // same as soundIn, but only plays on servers
22 | var input;
23 | input = ((..Udef.numChannels - 1) + bus).collect({ |item| SoundIn.ar( item ) });
24 | input = input.collect({ |input|
25 | input * if( bus > (NumInputBuses.ir - 1), 0, 1 );
26 | });
27 | UOut.ar( 0, input );
28 | }, channels: (1..8))
29 | .category_( \private )
30 | .shouldPlayOnFunc_({ |unit, target|
31 | if( WFSSpeakerConf.includesServer( target.asTarget.server ) ) {
32 | nil;
33 | } {
34 | false;
35 | };
36 | });
37 |
38 | def.udefs.do({ |item|
39 | item.setSpec( \bus, IntegerSpec( 0, 0, maxInput - item.numChannels )
40 | );
41 | });
42 |
43 | def;
--------------------------------------------------------------------------------
/WFS/UnitDefs/wfsStaticIndex.scd:
--------------------------------------------------------------------------------
1 | /*
2 | \wfsStaticIndex
3 |
4 | This udef can send sound to an individual speaker on the WFS system. The index of the speaker can not be changed in realtime (static); changes to the index will only become audible after the unit has been stopped and started again.
5 |
6 | indexFromBus: set to true if you want to set the index with a controller or by setting index.
7 | index: the number of the speaker, starting at 0.
8 | gain: the output level (dB).
9 |
10 | --
11 | this is an Udef definition file
12 | part of the WFSCollider Class Library default Udefs set
13 | */
14 |
15 | (
16 | var def;
17 | def = FreeUdef( \wfsStaticIndex, [
18 | [ \index: 0, PositiveIntegerSpec() ],
19 | [ \gain: -6, [ -96, 0, \db, 1, -6].asSpec ],
20 | ] )
21 | .category_( \private )
22 | .synthDef_(
23 | SynthDef( "wfsi_is", {
24 | var input, env, maxIndex;
25 | var gain = -10.dbamp;
26 | var index = 0, indexFromBus = 0;
27 |
28 | index = \index.kr(index); // not really static
29 | index = index - \startIndex.kr(0);
30 | gain = gain * \wfs_gain.ir(0).dbamp;
31 | gain = gain * \gain.kr(-6).dbamp;
32 | maxIndex = NumOutputBuses.ir; // only output to hardware outs
33 |
34 | gain = gain * InRange.kr(index, 0, maxIndex); // mute when out of range
35 |
36 | input = UGlobalEQ.ar( UIn.ar(0, 1) ) * gain * UEnv.kr;
37 |
38 | Out.ar( index.clip(0, maxIndex), input );
39 | })
40 | )
41 | .addSynthDefControls
42 | .setSpecMode( \index, \init )
43 | .shouldPlayOnFunc_({ |unit, target|
44 | target = target.asTarget.server;
45 | WFSSpeakerConf.includesServer( target ) && {
46 | unit.get( \index ).inclusivelyBetween(
47 | WFSSpeakerConf.default.firstSpeakerIndexOf( target ),
48 | WFSSpeakerConf.default.lastSpeakerIndexOf( target )
49 | );
50 | };
51 | })
52 | .createSynthFunc_({ |unit, target, startPos = 0|
53 | var startIndex;
54 | startIndex = WFSSpeakerConf.default.firstSpeakerIndexOf( target.asTarget.server );
55 | Synth( "wfsi_is", [
56 | \startIndex, startIndex - WFSSpeakerConf.getOutputBusStartOffset( target ),
57 | \wfs_gain, WFSSpeakerConf.default.gain
58 | ] ++
59 | unit.getArgsFor( target.asTarget.server, startPos ),
60 | target, \addToTail );
61 | });
62 |
63 | def.removeArgSpec( \startIndex ); // this is set by createSynthFunc
64 | def.removeArgSpec( \wfs_gain ); // this is set by createSynthFunc
65 |
66 | def.uchainInitFunc_({ |unit, chain|
67 | unit.def = \wfsIndex.asUdef;
68 | });
69 |
70 | def
71 | )
--------------------------------------------------------------------------------
/WFS/UnitRacks/wfsSimpleReverb.scd:
--------------------------------------------------------------------------------
1 | (
2 | // a position-dependant reverb scheme
3 | var points;
4 | points = [-6,6].collect({ |x| [-6,6].collect(x@_) }).flat;
5 |
6 | UnitRack(\wfsSimpleReverb, [
7 | \shared_point,
8 | [ \multiply, [
9 | 'mul', [ 'point_distance', [
10 | 'point1', 'shared_point_in',
11 | 'fromRange', [ 0.0, 15 ],
12 | 'toRange', [ 0.0, 0.5 ] ]
13 | ],
14 | 'u_o_ar_0_bus', 1
15 | ] ],
16 | [ 'delay', [
17 | 'time', [ 'point_distance', [
18 | 'point1', 'shared_point_in',
19 | 'fromRange', [ 0.0, 10.0 ],
20 | 'toRange', [ 0.0, 0.29 ],
21 | 'clipMode', 3 ]
22 | ], 'timeScale', 0.1, 'dry', 0.0, 'amp', 1.0,
23 | 'u_i_ar_0_bus', 1, 'u_o_ar_0_bus', 1
24 | ] ],
25 | [ 'duplicateChannel', [ 'u_i_ar_0_bus', 1, 'numChannels', 4 ] ++
26 | 4.collect({ |i| [ "u_o_ar_%_bus".format(i).asSymbol, i+1 ] }).flat
27 | ],
28 | ] ++ 4.collect({ |i|
29 | U( \freeverb, [
30 | 'mix', 1.0, 'room', i.linlin(0,3,0.47,0.53), 'damp', [
31 | 'point_distance', [
32 | 'point1', 'shared_point_in',
33 | 'fromRange', [ 0.0, 8.0 ]
34 | ] ], 'u_i_ar_0_bus', i+1, 'u_o_ar_0_bus', i+1
35 | ]
36 | )
37 | }) ++ points.collect({ |pt,i|
38 | U( 'wfsSource', [ 'point', pt, 'type', 'plane', 'u_i_ar_0_bus', i+1 ] )
39 | }) ++ [
40 | [ 'wfsSource', [ 'point', 'shared_point_in' ] ]
41 | ]
42 | ).category_( \wfs );
43 | )
--------------------------------------------------------------------------------
/WFS/UnitRacks/wfsTrajectory.scd:
--------------------------------------------------------------------------------
1 | UnitRack(\wfsPathPlayerTrack,
2 | [ U(\wfsSource, [ \point, UMap( \trajectory ) ] ) ]
3 | ).category_(\wfs)
--------------------------------------------------------------------------------
/WFS/WFSFocusDetector.sc:
--------------------------------------------------------------------------------
1 | WFSFocusDetector {
2 |
3 | var <>cornerPoints;
4 | var <>vectors;
5 | var <>size;
6 | var <>bypass = false;
7 |
8 | *new { |cornerPoints|
9 | ^super.newCopyArgs( cornerPoints ).init;
10 | }
11 |
12 | *basicNew { |cornerPoints, vectors, size|
13 | ^super.newCopyArgs( cornerPoints, vectors, size );
14 | }
15 |
16 | == { |that| // use === for identity
17 | ^this.compareObject(that);
18 | }
19 |
20 | init {
21 | size = cornerPoints.size;
22 | if( size < 3 ) {
23 | bypass = true
24 | } {
25 | vectors = size.collect({ |i|
26 | cornerPoints[i] - cornerPoints[(i-1).wrap(0,size-1)]
27 | });
28 | };
29 | }
30 |
31 | kr { |point = (0@0)|
32 | if( bypass ) { ^1 } {
33 | ^(vectors.collect({ |v,i|
34 | (
35 | (v.x * (point.y - cornerPoints[i].y)) - (v.y * (point.x - cornerPoints[i].x))
36 | ).sign
37 | }).sum.abs >= size).binaryValue;
38 | };
39 | }
40 | }
--------------------------------------------------------------------------------
/WFS/WFSFocusDetectorSynthDefs.sc:
--------------------------------------------------------------------------------
1 | WFSFocusDetectorSynthDefs : AbstractWFSSynthDefs {
2 |
3 | classvar <>minArrays = 4, <>maxArrays = 24;
4 |
5 | *prefix { ^"wfsfd" }
6 |
7 | *getDefName { |numArrays = 4|
8 |
9 | // example: "wfsf_8" : focus detection def for 8 arrays
10 |
11 | ^[ this.prefix, numArrays ].join("_");
12 | }
13 |
14 | *generateDef { |numArrays = 4|
15 |
16 | ^SynthDef( this.getDefName( numArrays ), {
17 |
18 | // synth args:
19 | var point = 0@0, pointFromBus = 0;
20 | var pointLag = 0;
21 | var outBus = 1999;
22 |
23 | // output:
24 | var output;
25 |
26 | pointFromBus = \pointFromBus.kr( pointFromBus );
27 | point = (\point.kr( point.asArray ) * (1-pointFromBus))
28 | + ( UIn.kr(0,2) * pointFromBus );
29 | pointLag = \pointLag.kr( pointLag );
30 | point = LPFLag.kr( point, pointLag );
31 | point = point.asPoint;
32 |
33 | outBus = \outBus.kr(1999);
34 |
35 | output = WFSFocusDetector.basicNew(
36 | \cornerPoints.ir( 0!(numArrays*2) ).clump(2).collect(_.asPoint),
37 | \vectors.ir( 0!(numArrays*2) ).clump(2).collect(_.asPoint),
38 | numArrays
39 | ).kr( point );
40 |
41 | ReplaceOut.kr( outBus, output );
42 |
43 | });
44 | }
45 |
46 | *generateAll { |action, dir|
47 | dir = dir ? SynthDef.synthDefDir;
48 | synthDefs = (minArrays..maxArrays).collect({ |numArrays|
49 | this.generateDef( numArrays );
50 | });
51 | action.value(this);
52 | ^synthDefs;
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSMultiPath.sc:
--------------------------------------------------------------------------------
1 | /*
2 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
3 | The Game Of Life Foundation. http://gameoflife.nl
4 | Copyright 2006-2011 Wouter Snoei.
5 |
6 | GameOfLife WFSCollider software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | GameOfLife WFSCollider is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with GameOfLife WFSCollider. If not, see .
18 | */
19 |
20 | WFSMultiPath {
21 | var <>paths;
22 | var <>fillTime = 0.1;
23 |
24 | prPathIndex { |index = 0|
25 | var sizes, pathIndex;
26 | sizes = paths.collect({ |item| item.positions.size }).integrate;
27 | pathIndex = sizes.detectIndex( index < _ );
28 | ^[ pathIndex, index - (sizes[ pathIndex - 1 ] ? 0) ]
29 | }
30 |
31 | at { |index|
32 | ^paths.at(index)
33 | }
34 |
35 | positions {
36 | ^paths.collect(_.positions).flatten(1);
37 | }
38 |
39 | positions_ { |positions|
40 | positions.clumps( paths.collect({|item|item.positions.size}) ).do({ |item, i|
41 | paths[i].positions = item;
42 | });
43 | }
44 |
45 | times {
46 | var times = [];
47 | paths.do({ |pth|
48 | times = times ++ pth.times
49 | });
50 | times;
51 | ^[]
52 | }
53 |
54 | times_ { |newTimes|
55 |
56 | }
57 |
58 | distances {
59 | ^[]
60 | }
61 |
62 | speeds {
63 | ^[]
64 | }
65 |
66 | forceTimes {
67 | // todo
68 | }
69 |
70 | length {
71 | ^paths.collect(_.length).maxItem;
72 | }
73 |
74 | asRect {
75 | ^if( paths.size > 0 ) {
76 | paths.collect(_.asRect).reduce(\union);
77 | } {
78 | Rect(0,0,0,0);
79 | }
80 | }
81 |
82 | name { ^"" }
83 | name_ { }
84 |
85 | type { ^\bspline }
86 | type_ { }
87 |
88 | curve { ^1 }
89 | curve_ { }
90 |
91 | clipMode { ^\clip }
92 | clipMode_ { }
93 |
94 | duration { ^this.paths.collect(_.duration).mean }
95 | duration_ { |dur|
96 | var oldDur;
97 | oldDur = this.duration;
98 | this.paths.do({ |item|
99 | item.duration = item.duration * ( dur / oldDur )
100 | });
101 | }
102 |
103 | asWFSPath2 { ^this }
104 |
105 | }
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/align.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \align,
3 | { |f, path, n|
4 | var direction, amount, mode;
5 | var current, mean, extent, size;
6 | current = path.positions.deepCopy;
7 | direction = f.get( \direction );
8 | mode = f.get( \mode );
9 | switch( mode,
10 | \line, {
11 | current = current.collect(_.rotate( direction * 0.5pi) );
12 | mean = current.collect(_.x).mean;
13 | current = current.collect({ |item|
14 | item.x = mean;
15 | item.rotate( direction * -0.5pi );
16 | });
17 | },
18 | \circle, {
19 | current = current.collect(_.asPolar);
20 | mean = current.collect(_.rho).mean;
21 | current = current.collect({ |item|
22 | item.rho = mean;
23 | item.asPoint;
24 | });
25 | },
26 | \spacing, {
27 | current = current.collect(_.rotate( direction * 0.5pi) );
28 | size = current.size;
29 | extent = [ current[0].y, current.last.y ];
30 | current = current.collect({ |item, i|
31 | item.y = i.linlin(0, size-1, extent[0], extent[1] );
32 | item.rotate( direction * -0.5pi ); });
33 | },
34 | \spacing_nearest, {
35 | current = current.collect(_.rotate( direction * 0.5pi) );
36 | extent = current.collect(_.y);
37 | size = extent.size;
38 | extent = [ extent.minItem, extent.maxItem ];
39 | current = current.collect({ |item, i|
40 | [ item, i ]
41 | }).sort( { |a,b| a[0].y <= b[0].y }).collect({ |item, i|
42 | item[0].y = i.linlin(0, size-1, *extent );
43 | [ item[0].rotate( direction * -0.5pi ), item[1] ]
44 | }).sort( { |a,b| a[1] <= b[1] } ).collect(_[0]);
45 | },
46 | );
47 | path.positions = current;
48 | },
49 | [ \direction, 0.0, \mode, \line ]
50 | )
51 | .changesT_( false )
52 | .setSpec( \direction, ControlSpec(0,1) )
53 | .setSpec( \mode, ListSpec([\line, \circle, \spacing, \spacing_nearest]) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/brown.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \brown,
3 | { |f, path, n|
4 | var center, radius, minRadius, angleStep, step;
5 | var wx, wy;
6 | var wr, wa;
7 | center = f.get( \center );
8 | radius = f.get( \radius );
9 | angleStep = (f.get( \angleStep ) / 360) * 2pi;
10 | step = f.get( \step );
11 | thisThread.randSeed = f.get( \seed );
12 | wr = Pbrown( 0, 1, step ).asStream;
13 | wa = Pseries( 0, Pwhite( angleStep.neg, angleStep ) ).asStream;
14 | path.positions = n.collect({
15 | (Polar( wr.next, wa.next ).asPoint * radius) + center
16 | });
17 | path;
18 | },
19 | [ \center, 0@0, \radius, 10@10,
20 | \angleStep, 20, \step, 0.125, \seed, 12345 ]
21 | )
22 | .changesT_( false )
23 | .setSpec( \seed, PositiveIntegerSpec(12345) )
24 | .setSpec( \center, PointSpec( 200, 0.1@0.1 ) )
25 | .setSpec( \radius, PointSpec( Rect(0,0,200,200), 0.1@0.1 ) )
26 | .setSpec( \angleStep, [0,360].asSpec )
27 | .setSpec( \step, [0,1].asSpec );
28 |
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/circle.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \circle,
3 | { |f, path, n|
4 | var clockwise, startAngle, center, radius, periods;
5 | var close, nn = n;
6 | clockwise = f.get( \clockwise ).binaryValue.linlin( 0,1,-1,1);
7 | startAngle = (f.get( \startAngle ) / 360) * 2pi;
8 | center = f.get( \center );
9 | radius = f.get( \radius );
10 | periods = f.get( \periods );
11 | close = f.get( \close );
12 | if( close ) { nn = n-1 };
13 | path.positions = n.collect({ |i|
14 | (((i.linlin(0,nn,0,2pi * periods) * clockwise) + [0,0.5pi] + startAngle)
15 | .sin.asPoint * radius) + center
16 | });
17 | path;
18 | },
19 | [ \periods, 1, \close, false, \startAngle,-90,
20 | \clockwise, true, \center, 0@0, \radius, 8@8
21 | ]
22 | )
23 | .changesT_( false )
24 | .setSpec( \periods, [0, inf, \lin, 0.125, 1].asSpec )
25 | .setSpec( \startAngle, [-180,180,\lin,1,0].asSpec )
26 | .setSpec( \center, PointSpec( 200, 0.1@0.1 ) )
27 | .setSpec( \radius, PointSpec( Rect(0,0,200,200), 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/line.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \line,
3 | { |f, path, n|
4 | var start, end, curve;
5 | start = f.get( \start );
6 | end = f.get( \end );
7 | curve = f.get( \curve );
8 | path.positions = n.collect({ |i|
9 | Point(
10 | i.lincurve(0,n-1,start.x,end.x,curve.x),
11 | i.lincurve(0,n-1,start.y,end.y,curve.y),
12 | );
13 | });
14 | },
15 | [ \start, 0@0, \end, 5@5, \curve, 0@0 ]
16 | )
17 | .changesT_( false )
18 | .setSpec( \start, PointSpec( 200, 0.1@0.1 ) )
19 | .setSpec( \end, PointSpec( 200, 0.1@0.1 ) )
20 | .setSpec( \curve, PointSpec( 10, 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/lineTime.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \lineTime,
3 | { |f, path, n|
4 | var start, end, curve, dur, nx;
5 | start = f.get( \start );
6 | end = f.get( \end );
7 | curve = f.get( \curve );
8 | dur = path.times.sum;
9 | nx = path.times.size - 1;
10 | path.times = path.times.collect({ |item, i|
11 | i.lincurve( 0, nx, start, end, curve ) * item }).normalizeSum( dur ) * dur;
12 | },
13 | [ \start, 0.5, \end, 2, \curve, 0 ]
14 | )
15 | .changesX_( false )
16 | .changesY_( false )
17 | .setSpec( \start, [0.01, 100, \exp, 0, 0.5].asSpec )
18 | .setSpec( \end, [0.01, 100, \exp, 0, 2].asSpec )
19 | .setSpec( \curve, [-16, 16, \lin, 0, 0].asSpec );
20 |
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/lissajous.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \lissajous,
3 | { |f, path, n|
4 | var startAngle, center, radius, periods;
5 | var close, nn = n;
6 | startAngle = (f.get( \startAngle ) / 360) * 2pi;
7 | center = f.get( \center );
8 | radius = f.get( \radius );
9 | periods = f.get( \periods );
10 | close = f.get( \close );
11 | if( close ) { nn = n-1 };
12 | path.positions = n.collect({ |i|
13 | (((i.linlin(0,nn,0,2pi * periods)) + [0,0.5pi] + startAngle)
14 | .sin.asPoint * radius) + center
15 | });
16 | path;
17 | },
18 | [ \periods, 1@1, \close, true, \startAngle, 0@0, \center, 0@0, \radius, 8@8 ]
19 | )
20 | .changesT_( false )
21 | .setSpec( \periods, PointSpec( 100, 1@1 ))
22 | .setSpec( \startAngle, PointSpec( 180, 0@0 ) )
23 | .setSpec( \center, PointSpec( 200, 0.1@0.1 ) )
24 | .setSpec( \radius, PointSpec( Rect(0,0,200,200), 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/orbit.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \orbit,
3 | { |f, path, n|
4 | var clockwise, startAngle, center, radius, periods;
5 | var close, nn = n;
6 | var eccentricity, eccentAngle;
7 | clockwise = f.get( \clockwise ).binaryValue.linlin( 0,1,-1,1);
8 | startAngle = (f.get( \startAngle ) / 360) * 2pi;
9 | center = f.get( \center );
10 | radius = f.get( \radius );
11 | periods = f.get( \periods );
12 | close = f.get( \close );
13 | eccentricity = f.get( \eccent ).clip( -0.999, 0.999 );
14 | eccentAngle = (f.get( \eccentAngle ) / 360) * 2pi;
15 | if( close ) { nn = n-1 };
16 | path.positions = n.collect({ |i|
17 | var r, v;
18 | v = (i.linlin(0,nn,0,2pi * periods) * clockwise) + startAngle + eccentAngle;
19 | r = (radius * (1-eccentricity.squared)) / (1 + (eccentricity * v.cos) );
20 | ( (v - eccentAngle + [0,0.5pi]).sin.asPoint * r ) + center
21 | });
22 | path;
23 | },
24 | [ \periods, 1, \close, false, \startAngle, 0,
25 | \clockwise, true, \center, 0@0, \radius, 8@8,
26 | \eccent, 0, \eccentAngle, 0
27 | ]
28 | )
29 | .changesT_( false )
30 | .setSpec( \periods, [0, inf, \lin, 0.125, 1].asSpec )
31 | .setSpec( \startAngle, [-180,180,\lin,1,0].asSpec )
32 | .setSpec( \center, PointSpec( 200, 0.1@0.1 ) )
33 | .setSpec( \radius, PointSpec( 200, 0.1@0.1 ) )
34 | .setSpec( \eccent, [-0.999,0.999,\lin,0,0].asSpec )
35 | .setSpec( \eccentAngle, [-180,180,\lin,1,0].asSpec );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/polygon.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \polygon,
3 | { |f, path, n|
4 | var sides, clockwise, orientation, offset, startAngle, center, radius, periods;
5 | var close, nn = n;
6 | var polygon;
7 | clockwise = f.get( \clockwise ).binaryValue.linlin( 0,1,-1,1);
8 | sides = f.get( \sides );
9 | orientation = f.get( \orientation );
10 | startAngle = (orientation / sides) * 2pi;
11 | center = f.get( \center );
12 | radius = f.get( \radius );
13 | offset = f.get( \offset );
14 | periods = f.get( \periods );
15 | close = f.get( \close );
16 | if( close ) { nn = n-1 };
17 | polygon = ((sides * periods).ceil).asInteger.collect({ |i|
18 | (((i.linlin(0,sides,0,2pi * periods) * clockwise) + [0,0.5pi] + startAngle)
19 | .sin.asPoint * radius) + center
20 | });
21 | path.positions = n.asInteger.collect({ |i|
22 | polygon.atL( ((i/nn) + offset ) * sides * periods );
23 | });
24 | path;
25 | },
26 | [ \sides, 6, \orientation, 0, \offset, 0.0, \periods, 1, \close, false,
27 | \clockwise, true, \center, 0@0, \radius, 8@8
28 | ]
29 | )
30 | .changesT_( false )
31 | .setSpec( \sides, [2, inf, \lin, 0.125, 6].asSpec )
32 | .setSpec( \periods, [0, inf, \lin, 0.125, 1].asSpec )
33 | .setSpec( \orientation, [-0.5,0.5,\lin,0,0].asSpec )
34 | .setSpec( \offset, [0.0,1.0,\lin,0,0].asSpec )
35 | .setSpec( \center, PointSpec( 200, 0.1@0.1 ) )
36 | .setSpec( \radius, PointSpec( Rect(0,0,200,200), 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/randTime.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \randTime,
3 | { |f, path, n|
4 | var min, max, seed, dur;
5 | min = f.get( \min );
6 | max = f.get( \max );
7 | seed = f.get( \seed );
8 | dur = path.times.sum;
9 | thisThread.randSeed = f.get( \seed );
10 | path.times = path.times.collect({ |item|
11 | (item * min) exprand: (item * max);
12 | }).normalizeSum( dur ) * dur;
13 | },
14 | [ \min, 0.5, \max, 2, \seed, 12345 ]
15 | )
16 | .changesX_( false )
17 | .changesY_( false )
18 | .setSpec( \min, [0.01, 100, \exp, 0, 0.5].asSpec )
19 | .setSpec( \max, [0.01, 100, \exp, 0, 2].asSpec )
20 | .setSpec( \seed, PositiveIntegerSpec(12345) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/random.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \random,
3 | { |f, path, n|
4 | var center, radius;
5 | center = f.get( \center );
6 | radius = f.get( \radius );
7 | thisThread.randSeed = f.get( \seed );
8 | path.positions = n.collect({
9 | (Polar( 1.0.rand, 2pi.rand ).asPoint * radius ) + center;
10 | });
11 | path;
12 | },
13 | [ \center, 0@0, \radius, 8@8, \seed, 12345 ]
14 | )
15 | .changesT_( false )
16 | .setSpec( \seed, PositiveIntegerSpec(12345) )
17 | .setSpec( \center, PointSpec( 200, 0.1@0.1 ) )
18 | .setSpec( \radius, PointSpec( Rect(0,0,200,200), 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/round.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \round,
3 | { |f, path, n|
4 | var precision, amount, mode;
5 | var current, mean, extent, size;
6 | current = path.positions.deepCopy;
7 | precision = f.get( \precision );
8 | mode = f.get( \mode );
9 | switch( mode,
10 | \xy, {
11 | current = current.collect(_.round( precision ) );
12 | },
13 | \angle, {
14 | current = current.collect({ |pt|
15 | pt.angle = (pt.angle / pi * 180).round( precision ) / 180 * pi;
16 | });
17 | },
18 | \distance, {
19 | current = current.collect({ |pt|
20 | pt.rho = pt.rho.round( precision );
21 | });
22 | },
23 | );
24 | path.positions = current;
25 | },
26 | [ \precision, 1.0, \mode, \xy ]
27 | )
28 | .changesT_( false )
29 | .setSpec( \precision, ControlSpec(0,200, 10.calcCurve(0,200), 0, 1 ) )
30 | .setSpec( \mode, ListSpec([\xy, \angle, \distance]) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/sine.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \sine,
3 | { |f, path, n|
4 | var start, end, phase, amp, periods;
5 | var polar;
6 | start = f.get( \start );
7 | end = f.get( \end );
8 | periods = f.get( \periods );
9 | amp = f.get( \amp );
10 | phase = f.get( \phase ) * pi;
11 | polar = (end - start).asPolar;
12 | path.positions = n.collect({ |i|
13 | var sin;
14 | sin = (i.linlin(0,n-1,0,2pi * periods) + phase).sin * amp;
15 | ( i.linlin(0,n-1,0,polar.rho) @ sin ).rotate( polar.theta ) + start;
16 | });
17 | path;
18 | },
19 | [ \periods, 1, \phase, 0, \start, 0@0, \end, 5@5, \amp, 2 ]
20 | )
21 | .changesT_( false )
22 | .setSpec( \periods, [0, inf, \lin, 0.125].asSpec )
23 | .setSpec( \phase, [0, 2, \lin].asSpec )
24 | .setSpec( \start, PointSpec( 200, 0.1@0.1 ) )
25 | .setSpec( \end, PointSpec( 200, 0.1@0.1 ) )
26 | .setSpec( \amp, [ -inf, inf, \lin, 0.125 ].asSpec );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/spiral.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \spiral,
3 | { |f, path, n|
4 | var clockwise, startAngle, center, radius, periods;
5 | var close, nn = n;
6 | clockwise = f.get( \clockwise ).binaryValue.linlin( 0,1,-1,1);
7 | startAngle = (f.get( \startAngle ) / 360) * 2pi;
8 | center = [ f.get( \startCenter ), f.get( \endCenter ) ];
9 | radius = [ f.get( \startRadius ), f.get( \endRadius ) ];
10 | periods = f.get( \periods );
11 | close = f.get( \close );
12 | if( close ) { nn = n-1 };
13 | path.positions = n.collect({ |i|
14 | (((i.linlin(0,nn,0,2pi * periods) * clockwise) + [0,0.5pi] + startAngle)
15 | .sin.asPoint * radius[0].blend(radius[1], i/nn) )
16 | + center[0].blend(center[1], i/nn)
17 | });
18 | path;
19 | },
20 | [ \periods, 1, \close, true, \startAngle, 0,
21 | \clockwise, true, \startCenter, 0@0, \startRadius, 8@8,
22 | \endCenter, 0@0, \endRadius, 0@0,
23 | ]
24 | )
25 | .changesT_( false )
26 | .setSpec( \periods, [0, inf, \lin, 0.125, 1].asSpec )
27 | .setSpec( \startAngle, [-180,180,\lin,1,0].asSpec )
28 | .setSpec( \startCenter, PointSpec( 200, 0.1@0.1 ) )
29 | .setSpec( \startRadius, PointSpec( Rect(0,0,200,200), 0.1@0.1 ) )
30 | .setSpec( \endCenter, PointSpec( 200, 0.1@0.1 ) )
31 | .setSpec( \endRadius, PointSpec( Rect(-200,-200,400,400), 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathGeneratorDefs/spline.scd:
--------------------------------------------------------------------------------
1 | WFSPathGeneratorDef(
2 | \spline,
3 | { |f, path, n|
4 | var start, end, c1, c2;
5 | var part1;
6 | start = f.get( \start );
7 | end = f.get( \end );
8 | c1 = f.get( \c1 );
9 | c2 = f.get( \c2 );
10 | part1 = [ start, end ].splineIntPart1( c1, c2 );
11 | path.positions = n.collect({ |i|
12 | part1.splineIntPart2( i / (n-1) )
13 | });
14 | path;
15 | },
16 | [ \start, 0@0, \end, 5@5, \c1, 0@5, \c2, 5@0 ]
17 | )
18 | .changesT_( false )
19 | .setSpec( \start, PointSpec( 200, 0.1@0.1 ) )
20 | .setSpec( \end, PointSpec( 200, 0.1@0.1 ) )
21 | .setSpec( \c1, PointSpec( 200, 0.1@0.1 ) )
22 | .setSpec( \c2, PointSpec( 200, 0.1@0.1 ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/circleSize.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \circleSize,
2 | { |f, path|
3 | var angles, distances;
4 | var newPos, newTimes;
5 | var n;
6 | n = f.get( \size ).asInteger;
7 | if( path.repondsTo( \times ) ) {
8 | newTimes = [0] ++ path.times.integrate;
9 | newTimes = newTimes.resize( n, \linear, false ).differentiate[1..];
10 | path.times = newTimes;
11 | };
12 | angles = path.positions.collect(_.angle);
13 | distances = path.positions.collect(_.rho);
14 |
15 | newPos = path.positions.resize( n, \hermite, true );
16 | path.positions_( newPos );
17 | },
18 | [ \size, 10 ],
19 | { |f, path| [ \size, path.positions.size ] }
20 | )
21 | .setSpec( \size, PositiveIntegerSpec(2, 2) )
22 | .useSelection_( false );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/clip.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \clip, { |f, path|
2 | var range;
3 | var obj, center;
4 | if( f.get( \clip ) != \off ) {
5 | center = f.get( \clipCenter );
6 | obj = path.positions.collect( _ - center );
7 | range = f.get( \clipRadius );
8 | if( f.get( \polar ) == true ) {
9 | range = range.clip(1.0e-12, inf);
10 | obj = obj.collect({ |item| item = (item / range).asPolar; [item.rho, item.theta] }).flop;
11 | obj[0] = switch( f.get( \clip ),
12 | \softClip, { obj[0].softclip2(1, f.get( \clipSoftness ) ) },
13 | \sineClip, { obj[0].sineclip2(1, f.get( \clipSoftness ) ); },
14 | \fold, { obj[0].softfold2(1, f.get( \clipSoftness ) ); },
15 | \wrap, { obj[0].softwrap2(1, f.get( \clipSoftness ) ); },
16 | \excess, { obj[0].softexcess2(1, f.get( \clipSoftness ) ); },
17 | { obj[0] }
18 | );
19 | obj = obj.flop.collect({ |item| Polar( item[0], item[1] ).asPoint * range });
20 | } {
21 | obj = switch( f.get( \clip ),
22 | \softClip, { obj.softclip2(range, f.get( \clipSoftness ) * range ) },
23 | \sineClip, { obj.sineclip2(range, f.get( \clipSoftness ) * range ); },
24 | \fold, { obj.softfold2(range, f.get( \clipSoftness ) * range ); },
25 | \wrap, { obj.softwrap2(range, f.get( \clipSoftness ) ); },
26 | \excess, { obj.softexcess2(range, f.get( \clipSoftness ) * range ); },
27 | { obj }
28 | );
29 | };
30 | path.positions = obj.collect( _ + center );
31 | };
32 | }, [ \clip, \off, \clipSoftness, 0.0, \clipCenter, 0@0, \clipRadius, 5@5, \polar, false ] )
33 | .setSpec( \clipCenter, PointSpec(200) )
34 | .setSpec( \clipRadius, PointSpec(Rect(0,0,200,200)) )
35 | .setSpec( \clip, ListSpec( [ \softClip, \sineClip, \fold, \wrap, \excess, \off ] ) )
36 | .setSpec( \polar, BoolSpec( false ) )
37 | .setSpec( \clipSoftness,[0,1].asSpec );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/duration.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \duration,
2 | { |f, path|
3 | var tms, origTms, seldur, dur, adddur;
4 | var sel;
5 | sel = f.selection;
6 | if( sel.size > 0 ) {
7 | origTms = path.times;
8 | tms = origTms.clipAt(sel);
9 | seldur = tms.sum;
10 | dur = path.times.sum;
11 | adddur = f.get( \duration ) - dur;
12 | tms = (tms.normalizeSum * (seldur + adddur)).max(0.001);
13 | tms.do({ |tm, i|
14 | origTms[ sel[i] ] = tm;
15 | });
16 | path.times = origTms;
17 | };
18 | path.times = path.times.normalizeSum * f.get( \duration );
19 | },
20 | [ \duration, 1 ],
21 | { |f, path| [ \duration, path.duration ] }
22 | )
23 | .setSpec( \duration, SMPTESpec(0.001) )
24 | .useSelection_( false );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/equal.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \equal,
2 | { |f, path|
3 | var oldTimes, deltas;
4 | var newPos, equalTimes, newTimes;
5 | var mode, amt;
6 |
7 | mode = f.get( \equal );
8 | amt = f.get( \amount );
9 | oldTimes = path.times;
10 | equalTimes = oldTimes.blend(
11 | ((1/oldTimes.size) * oldTimes.sum)!(oldTimes.size),
12 | amt
13 | );
14 |
15 | switch( mode,
16 | \times, {
17 | newTimes = equalTimes;
18 | },
19 | \speeds, {
20 | deltas = path.positions[1..].collect({ |pos, i|
21 | pos.dist( path.positions[i] )
22 | }).normalizeSum;
23 | oldTimes = path.times;
24 | newTimes = oldTimes.blend(
25 | deltas * oldTimes.sum,
26 | amt
27 | );
28 | path.times = newTimes;
29 | }
30 | );
31 |
32 | if( f.get( \resample ) == true ) {
33 |
34 | newPos = ([0] ++ equalTimes.integrate).collect({ |item|
35 | path.atTime( item );
36 | });
37 | path.positions = newPos;
38 | newTimes = equalTimes;
39 | };
40 | newTimes = newTimes.max(0); // clip negative times
41 | path.times_( newTimes );
42 | },
43 | [ \equal, \times, \amount, 0, \resample, false ],
44 | { |f, path| [ \equal, f.get( \equal ), \amount, 0, \resample, f.get( \resample ) ] }
45 | )
46 | .setSpec( \equal, ListSpec( [ \times, \speeds ] ))
47 | .setSpec( \amount, ControlSpec(-1,1,\lin,0,0) )
48 | .setSpec( \resample, BoolSpec( false ) )
49 | .useSelection_( false );
50 |
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/move.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \move,
2 | { |f, path|
3 | var toCenterAmt = 0;
4 | if( f.get( \center ) == true ) {
5 | toCenterAmt = path.positions.mean
6 | };
7 | path.positions_( path.positions + [f.get( \move ) - toCenterAmt ] );
8 | },
9 | [ \center, false, \move, 0@0 ]
10 | )
11 | .setSpec( \move, PointSpec( 200, 0.1 ) )
12 | .setSpec( \center, BoolSpec(false) )
13 | .useSelection_( true );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/name.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \name,
2 | { |f, obj| obj.name_( f.get( \name ) ) },
3 | [ \name, "" ],
4 | { |f, obj| [ \name, obj.name ] }
5 | ) .setSpec( \name, StringSpec() )
6 | .useSelection_( false );
7 |
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/reverse.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \reverse,
2 | { |f, path|
3 | var positions;
4 | switch( f.get( \reverse ),
5 | \all, {
6 | path.positions = path.positions.reverse;
7 | path.times = path.times.reverse;
8 | },
9 | \x, {
10 | positions = path.positions.collect(_.asArray).flop;
11 | positions[0] = positions[0].reverse;
12 | path.positions = positions.flop.collect(_.asPoint);
13 | },
14 | \y, {
15 | positions = path.positions.collect(_.asArray).flop;
16 | positions[1] = positions[1].reverse;
17 | path.positions = positions.flop.collect(_.asPoint);
18 | },
19 | \angles, {
20 | positions = path.positions.collect({|x|
21 | x = x.asPolar;
22 | [ x.rho, x.theta ]
23 | }).flop;
24 | positions[1] = positions[1].reverse;
25 | path.positions = positions.flop.collect({|x|
26 | Polar( *x ).asPoint
27 | });
28 | },
29 | \distances, {
30 | positions = path.positions.collect({|x|
31 | x = x.asPolar;
32 | [ x.rho, x.theta ]
33 | }).flop;
34 | positions[0] = positions[0].reverse;
35 | path.positions = positions.flop.collect({|x|
36 | Polar( *x ).asPoint
37 | });
38 | },
39 | \positions, {
40 | path.positions = path.positions.reverse;
41 | },
42 | \times, {
43 | path.times = path.times.reverse;
44 | }
45 | );
46 | path;
47 | },
48 | [ \reverse, \off ]
49 | )
50 | .setSpec( \reverse, ListSpec([ \off, \all, \x, \y, \angles, \distances, \positions, \times ]) )
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/rotate.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \rotate,
2 | { |f, path|
3 | var rotate;
4 | rotate = (f.get( \rotate ).neg / 360) * 2pi;
5 | path.positions_( path.positions.collect(_.rotate(rotate)) );
6 | },
7 | [ \rotate, 0 ]
8 | )
9 | .setSpec( \rotate, ControlSpec( -180, 180, \lin, 0, 1 ) )
10 | .useSelection_( true );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/scale.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \scale,
2 | { |f, path| path.positions_( path.positions * [f.get( \scale ) ] ); },
3 | [ \scale, 1@1 ]
4 | )
5 | .setSpec( \scale, PointSpec( 10, 0.1 ) )
6 | .useSelection_( true );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/simpleSize.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \simpleSize,
2 | { |f, path|
3 | var oldTimes;
4 | var newPos, newTimes;
5 | var n;
6 | n = f.get( \size ).asInteger;
7 | newTimes = [0] ++ path.times.integrate;
8 | newTimes = newTimes.resize( n, \linear, false );
9 | newPos = newTimes.collect({ |item| path.atTime( item ) });
10 | newTimes = newTimes.differentiate[1..];
11 | path.positions_( newPos ).times_( newTimes );
12 | },
13 | [ \size, 10 ],
14 | { |f, path| [ \size, path.positions.size ] }
15 | )
16 | .setSpec( \size, PositiveIntegerSpec(2, 2) )
17 | .useSelection_( false );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/size.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \size,
2 | { |f, path|
3 | var oldTimes;
4 | var newPos, newTimes;
5 | var mode, n;
6 | mode = f.get( \mode );
7 | n = f.get( \size ).asInteger;
8 | switch( mode,
9 | \interpolate, {
10 | newTimes = [0] ++ path.times.integrate;
11 | newTimes = newTimes.resize( n, \linear, false );
12 | newPos = newTimes.collect({ |item| path.atTime( item ) });
13 | newTimes = newTimes.differentiate[1..];
14 | },
15 | \wrap, {
16 | oldTimes = path.times ++ [ path.times.last ];
17 | newPos = n.collect({ |i|
18 | path.positions.wrapAt( i ).copy;
19 | });
20 | newTimes = n.collect({ |i|
21 | oldTimes.wrapAt( i );
22 | });
23 | newTimes.pop;
24 | oldTimes.pop;
25 | newTimes = newTimes.normalizeSum( oldTimes.sum );
26 | },
27 | \fold, {
28 | oldTimes = path.times ++ [ path.times.last ];
29 | newPos = n.collect({ |i|
30 | path.positions.foldAt( i ).copy;
31 | });
32 | newTimes = n.collect({ |i|
33 | oldTimes.foldAt( i );
34 | });
35 | newTimes.pop;
36 | oldTimes.pop;
37 | newTimes = newTimes.normalizeSum( oldTimes.sum );
38 |
39 | }
40 | );
41 | path.positions_( newPos ).times_( newTimes );
42 | },
43 | [ \size, 10, \mode, \interpolate ],
44 | { |f, path| [ \size, path.positions.size, \mode, f.get( \mode ) ] }
45 | )
46 | .setSpec( \size, PositiveIntegerSpec(2, 2) )
47 | .setSpec( \mode, ListSpec( [ \interpolate, \wrap, \fold ] ) )
48 | .useSelection_( false );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/smooth.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \smooth,
2 | { |f, path|
3 | var newPos, win, n, amt;
4 | n = (f.get( \window ) * path.positions.size).max(3);
5 | amt = f.get( \smooth );
6 | win = ({ |i|
7 | i.linlin(0,(n-1).max(2),-0.5pi,1.5pi).sin.linlin(-1,1,0,1)
8 | }!n.max(2)).normalizeSum;
9 | newPos = path.positions.collect({ |item, i|
10 | var out, sum;
11 | out = path.positions.modeAt(
12 | (i + (n/ -2).ceil .. i + (n/2).ceil - 1), path.clipMode ) * win;
13 | sum = 0@0;
14 | out.do({ |item| sum = sum + item; });
15 | sum;
16 | });
17 |
18 | path.positions_(
19 | path.positions.collect({ |item, i| item.blend( newPos[i], amt ) })
20 | );
21 | },
22 | [ \smooth, 0, \window, 0.3 ],
23 | { |f, path| [ \smooth, 0, \window, f.get( \window) ] }
24 | )
25 | .setSpec( \smooth, ControlSpec( -1, 1, \lin, 0, 0 ) )
26 | .setSpec( \window, ControlSpec( 0, 1, \lin, 0.1, 0.3 ) )
27 | .useSelection_( false );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/sort.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \sort,
2 | { |f, path|
3 | var sortedPos, oldPos, type;
4 | type = f.get( \sort );
5 | if( type != \scramble ) { f.environment[ \seed ] = nil; };
6 | switch( type,
7 | \distance, {
8 | sortedPos = path.positions.deepCopy.sort({ |a,b|
9 | a.rho <= b.rho;
10 | });
11 | },
12 | \angle, {
13 | sortedPos = path.positions.deepCopy.sort({ |a,b|
14 | a.theta <= b.theta;
15 | });
16 | },
17 | \scramble, {
18 | if( f.environment[ \seed ].isNil ) {
19 | f.environment[ \seed ] = 1569325056.rand;
20 | };
21 | thisThread.randSeed = f.environment[ \seed ];
22 | sortedPos = path.positions.deepCopy.scramble;
23 | },
24 | \nearest, {
25 | oldPos = path.positions.reverse;
26 | sortedPos = Array( oldPos.size );
27 | sortedPos.add( oldPos.pop );
28 | oldPos.size.do({
29 | oldPos.sort({ |a,b|
30 | a.dist( sortedPos.last ) >= b.dist( sortedPos.last )
31 | });
32 | sortedPos.add( oldPos.pop );
33 | });
34 | },
35 | \rel_angle, {
36 | oldPos = path.positions.reverse;
37 | sortedPos = Array( oldPos.size );
38 | sortedPos.add( oldPos.pop );
39 | if( oldPos.size > 0 ) { sortedPos.add( oldPos.pop ); };
40 | oldPos.size.do({
41 | var lastAngle;
42 | lastAngle = (sortedPos.last - sortedPos[ sortedPos.size - 2 ]).angle;
43 | oldPos.sort({ |a,b|
44 | var aa, bb;
45 | aa = lastAngle - ((a - sortedPos.last).angle).wrap(-pi,pi);
46 | bb = lastAngle - ((b - sortedPos.last).angle).wrap(-pi,pi);
47 | if( aa.abs.round(0.01pi) == bb.abs.round(0.01pi) ) {
48 | a.dist( sortedPos.last ) >= b.dist( sortedPos.last )
49 | } {
50 | aa.abs >= bb.abs
51 | };
52 | });
53 | sortedPos.add( oldPos.pop );
54 | });
55 | },
56 | \x, {
57 | sortedPos = path.positions.deepCopy.sort({ |a,b|
58 | a.x <= b.x;
59 | });
60 | },
61 | \y, {
62 | sortedPos = path.positions.deepCopy.sort({ |a,b|
63 | a.y <= b.y;
64 | });
65 | },
66 | \mean_xy, {
67 | sortedPos = path.positions.deepCopy.sort({ |a,b|
68 | (a.x + a.y) <= (b.x + b.y);
69 | });
70 | }
71 | );
72 | if( sortedPos.notNil ) { path.positions_(sortedPos); };
73 | },
74 | [ \sort, \off ]
75 | )
76 | .setSpec( \sort, ListSpec( [ \off, \distance, \angle, \scramble, \nearest, \rel_angle, \x, \y, \mean_xy ] ) );
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSPathTransformerDefs/type.scd:
--------------------------------------------------------------------------------
1 | WFSPathTransformerDef( \type,
2 | { |f, obj| obj
3 | .type_( f.get( \type ) )
4 | .curve_( f.get( \curve ) )
5 | .clipMode_( f.get( \clipMode ) );
6 | },
7 | [ \type, \bspline, \curve, 1.0, \clipMode, \clip ],
8 | { |f, obj| [ \type, obj.type, \curve, obj.curve, \clipMode, obj.clipMode ] }
9 | )
10 | .setSpec( \type, ListSpec( [ \bspline, \cubic, \linear ] ) )
11 | .setSpec( \curve, ControlSpec( 0, 2, \lin, 0.1, 1 ) )
12 | .setSpec( \clipMode, ListSpec( [ \clip, \wrap, \fold ] ) )
13 | .useSelection_( false );
14 |
--------------------------------------------------------------------------------
/WFS/WFSPath/WFSSplinePath.sc:
--------------------------------------------------------------------------------
1 | /*
2 | GameOfLife WFSCollider - Wave Field Synthesis spatialization for SuperCollider.
3 | The Game Of Life Foundation. http://gameoflife.nl
4 | Copyright 2006-2011 Wouter Snoei.
5 |
6 | GameOfLife WFSCollider software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | GameOfLife WFSCollider is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with GameOfLife WFSCollider. If not, see .
18 | */
19 |
20 | WFSSplinePath : WFSPath2 {
21 |
22 | var