From 34bdac25f1f42edf04058c9ab51f0fbf9875cc05 Mon Sep 17 00:00:00 2001 From: dkmayer Date: Tue, 21 Apr 2020 21:54:14 +0200 Subject: [PATCH] miSCellaneous v0.23 --- .gitattributes.txt | 1 + .gitignore.txt | 4 + Classes/DX/AbstractDX.sc | 527 ++++ Classes/DX/extUGen.sc | 94 + Classes/Enumeration/extInteger.sc | 67 + Classes/FFT/PV_UGens.sc | 73 + Classes/FFT/extFFT.sc | 30 + Classes/FFT/extSequenceableCollection.sc | 30 + Classes/HS/HelpSynth.sc | 338 +++ Classes/HS/HelpSynthPar.sc | 217 ++ Classes/HS/PHelpSynth.sc | 77 + Classes/HS/PHelpSynthPar.sc | 132 + Classes/HS/PHelpSynthParPlayer.sc | 185 ++ Classes/HS/PHelpSynthParUse.sc | 210 ++ Classes/HS/PHelpSynthPlayer.sc | 146 ++ Classes/HS/PHelpSynthUse.sc | 230 ++ Classes/HS/PHelpSynthUsePlayer.sc | 114 + Classes/HS/extHelpSynth.sc | 79 + Classes/HS/extObject.sc | 67 + Classes/HS/extSequenceableCollection.sc | 89 + Classes/HS/extSynth.sc | 33 + Classes/HS/extTempoClock.sc | 36 + Classes/HS/extThread.sc | 43 + Classes/Nonlinear/Fb1.sc | 636 +++++ Classes/Nonlinear/Fb1_ODE.sc | 649 +++++ Classes/Nonlinear/Fb1_ODEdef.sc | 275 +++ Classes/Nonlinear/Fb1_ODEintdef.sc | 606 +++++ Classes/Nonlinear/GFIS.sc | 55 + Classes/Nonlinear/extObject.sc | 29 + .../Nonlinear/extSequenceableCollection.sc | 86 + Classes/Nonlinear/extUGen.sc | 28 + Classes/Other/DIdev.sc | 125 + Classes/Other/extPlatform.sc | 51 + Classes/Other/extUGen.sc | 31 + Classes/Patterns/AddEventTypes_PbindFx.sc | 282 +++ Classes/Patterns/EventShortcuts.sc | 263 ++ Classes/Patterns/MemoRoutine.sc | 78 + Classes/Patterns/OtherPatterns.sc | 275 +++ Classes/Patterns/PIdev.sc | 92 + Classes/Patterns/PL.sc | 757 ++++++ Classes/Patterns/PL_ListProxy.sc | 176 ++ Classes/Patterns/PLbindef.sc | 132 + Classes/Patterns/PLbindefPar.sc | 274 +++ Classes/Patterns/PS.sc | 141 ++ Classes/Patterns/PSPdiv.sc | 210 ++ Classes/Patterns/PbindFx.sc | 111 + Classes/Patterns/Pclutch_PbindFx.sc | 53 + Classes/Patterns/extDictionary.sc | 30 + Classes/Patterns/extEvent.sc | 34 + Classes/Patterns/extIdentityDictionary.sc | 47 + Classes/Patterns/extObject.sc | 43 + Classes/Patterns/extObject_2.sc | 55 + Classes/Patterns/extPattern.sc | 39 + Classes/Patterns/extPbindFx_1.sc | 250 ++ Classes/Patterns/extPbindFx_2.sc | 185 ++ Classes/Patterns/extPbindFx_3.sc | 305 +++ Classes/Patterns/extPbindFx_4.sc | 87 + Classes/Patterns/extSequenceableCollection.sc | 65 + Classes/Patterns/extStream.sc | 29 + Classes/Patterns/extSymbol.sc | 40 + Classes/Sieves/Psieve.sc | 363 +++ Classes/Sieves/Sieve.sc | 601 +++++ Classes/Sieves/lcmExtensions.sc | 117 + Classes/Sieves/periods.sc | 160 ++ Classes/Sieves/streamifySieveItems.sc | 48 + Classes/Sieves/toSieve.sc | 115 + Classes/VarGui/SimpleInitError.sc | 41 + Classes/VarGui/SimpleInputError.sc | 49 + Classes/VarGui/VarGui.sc | 469 ++++ Classes/VarGui/VarGuiPlayerSection.sc | 1193 +++++++++ Classes/VarGui/extBoolean.sc | 43 + Classes/VarGui/extCollection.sc | 49 + Classes/VarGui/extColor.sc | 45 + Classes/VarGui/extControlSpec.sc | 39 + Classes/VarGui/extDictionary.sc | 30 + Classes/VarGui/extEZSlider.sc | 84 + Classes/VarGui/extFloat.sc | 77 + Classes/VarGui/extFunction.sc | 34 + Classes/VarGui/extFunctionDef.sc | 34 + Classes/VarGui/extInteger_1.sc | 114 + Classes/VarGui/extInteger_2.sc | 97 + Classes/VarGui/extInteger_3.sc | 51 + Classes/VarGui/extNil.sc | 27 + Classes/VarGui/extNode.sc | 45 + Classes/VarGui/extObject.sc | 48 + Classes/VarGui/extOther.sc | 57 + Classes/VarGui/extPauseStream.sc | 32 + Classes/VarGui/extSequenceableCollection_1.sc | 58 + Classes/VarGui/extSequenceableCollection_2.sc | 200 ++ Classes/VarGui/extSimpleNumber.sc | 30 + Classes/VarGui/extString_1.sc | 30 + Classes/VarGui/extString_2.sc | 66 + Classes/VarGui/extSymbol_1.sc | 35 + Classes/VarGui/extSymbol_2.sc | 287 +++ Classes/VarGui/extSynth.sc | 30 + Classes/VarGui/extVarGuiPlayerSection.sc | 84 + Classes/VarGui/extVarGui_1.sc | 385 +++ Classes/VarGui/extVarGui_2.sc | 141 ++ Classes/VarGui/extVarGui_3.sc | 228 ++ Classes/VarGui/extVarGui_4.sc | 216 ++ Classes/VarGui/extVarGui_5.sc | 74 + Classes/VarGui/extVarGui_6.sc | 176 ++ Classes/WaveFolding/SmoothClip.sc | 150 ++ Classes/WaveFolding/SmoothFold.sc | 157 ++ Classes/ZeroX/TZeroXBufRd.sc | 185 ++ Classes/ZeroX/ZeroXBufRd.sc | 225 ++ Classes/ZeroX/ZeroXBufWr.sc | 155 ++ Classes/ZeroX/extBuffer.sc | 55 + Help/Buffer Granulation.html | 1714 +++++++++++++ Help/DIdev.html | 449 ++++ Help/DX suite.html | 169 ++ Help/DXEnvFan.html | 789 ++++++ Help/DXEnvFanOut.html | 283 +++ Help/DXFan.html | 393 +++ Help/DXFanOut.html | 346 +++ Help/DXMix.html | 1036 ++++++++ Help/DXMixIn.html | 286 +++ Help/Event patterns and Functions.html | 338 +++ Help/Event patterns and LFOs.html | 582 +++++ Help/Event patterns and array args.html | 680 ++++++ Help/EventShortcuts.html | 322 +++ Help/Fb1.html | 1585 ++++++++++++ Help/Fb1_Duffing.html | 324 +++ Help/Fb1_Hopf.html | 359 +++ Help/Fb1_HopfA.html | 366 +++ Help/Fb1_HopfAFDC.html | 406 +++ Help/Fb1_Lorenz.html | 358 +++ Help/Fb1_MSD.html | 324 +++ Help/Fb1_ODE.html | 1129 +++++++++ Help/Fb1_ODEdef.html | 441 ++++ Help/Fb1_ODEintdef.html | 180 ++ Help/Fb1_SD.html | 325 +++ Help/Fb1_VanDerPol.html | 348 +++ Help/GFIS.html | 538 ++++ Help/HS with VarGui.html | 388 +++ Help/HS.html | 277 +++ Help/HSpar.html | 139 ++ Help/Idev suite.html | 49 + Help/Introduction to miSCellaneous.html | 589 +++++ Help/Live Granulation.html | 938 +++++++ Help/MemoRoutine.html | 266 ++ Help/Other event and pattern shortcuts.html | 297 +++ Help/PHS.html | 222 ++ Help/PHSpar.html | 415 ++++ Help/PHSparPlayer.html | 328 +++ Help/PHSparUse.html | 222 ++ Help/PHSplayer.html | 145 ++ Help/PHSuse.html | 169 ++ Help/PHSusePlayer.html | 156 ++ Help/PIdev.html | 342 +++ Help/PL.html | 173 ++ Help/PLIdev.html | 381 +++ Help/PLbeta.html | 140 ++ Help/PLbindef.html | 380 +++ Help/PLbindefEnvironment.html | 92 + Help/PLbindefPar.html | 511 ++++ Help/PLbindefParEnvironment.html | 58 + Help/PLbrown.html | 119 + Help/PLcauchy.html | 114 + Help/PLexprand.html | 114 + Help/PLgauss.html | 115 + Help/PLgbrown.html | 126 + Help/PLgeom.html | 115 + Help/PLhprand.html | 118 + Help/PLlprand.html | 118 + Help/PLmeanrand.html | 117 + Help/PLn.html | 254 ++ Help/PLnaryFunc.html | 126 + Help/PLnaryop.html | 119 + Help/PLpoisson.html | 107 + Help/PLrand.html | 177 ++ Help/PLseq.html | 171 ++ Help/PLser.html | 144 ++ Help/PLseries.html | 120 + Help/PLshuf.html | 179 ++ Help/PLshufn.html | 188 ++ Help/PLslide.html | 194 ++ Help/PLswitch.html | 192 ++ Help/PLswitch1.html | 197 ++ Help/PLtuple.html | 124 + Help/PLwalk.html | 222 ++ Help/PLwhite.html | 113 + Help/PLwrand.html | 131 + Help/PLx and live coding with Strings.html | 778 ++++++ Help/PLx suite.html | 606 +++++ Help/PLxrand.html | 187 ++ Help/PS.html | 291 +++ Help/PSPdiv.html | 542 ++++ Help/PSVdif.html | 82 + Help/PSVdif_i.html | 82 + Help/PSVdif_o.html | 83 + Help/PSVdif_oi.html | 83 + Help/PSVop.html | 105 + Help/PSVop_i.html | 105 + Help/PSVop_o.html | 108 + Help/PSVop_oi.html | 110 + Help/PSVsect.html | 83 + Help/PSVsect_i.html | 83 + Help/PSVsect_o.html | 83 + Help/PSVsect_oi.html | 82 + Help/PSVsymdif.html | 82 + Help/PSVsymdif_i.html | 84 + Help/PSVsymdif_o.html | 84 + Help/PSVsymdif_oi.html | 83 + Help/PSVunion.html | 81 + Help/PSVunion_i.html | 83 + Help/PSVunion_o.html | 84 + Help/PSVunion_oi.html | 84 + Help/PSdup.html | 205 ++ Help/PSloop.html | 725 ++++++ Help/PSrecur.html | 152 ++ Help/PSx stream patterns.html | 100 + Help/PV_BinGap.html | 140 ++ Help/PV_BinRange.html | 141 ++ Help/PbindFx.html | 2171 +++++++++++++++++ Help/PlaceAll.html | 112 + Help/PmonoPar.html | 174 ++ Help/PpolyPar.html | 497 ++++ Help/Pshufn.html | 76 + Help/Psieve.html | 40 + Help/PsymNilSafe.html | 88 + Help/Sieve.html | 720 ++++++ Help/Sieves and Psieve patterns.html | 1343 ++++++++++ Help/Smooth Clipping and Folding.html | 229 ++ Help/SmoothClipQ.html | 73 + Help/SmoothClipS.html | 72 + Help/SmoothFoldQ.html | 75 + Help/SmoothFoldQ2.html | 79 + Help/SmoothFoldS.html | 77 + Help/SmoothFoldS2.html | 80 + Help/TZeroXBufRd.html | 734 ++++++ Help/VarGui shortcut builds.html | 1099 +++++++++ Help/VarGui.html | 1561 ++++++++++++ Help/Working with HS and HSpar.html | 147 ++ Help/ZeroXBufRd.html | 889 +++++++ Help/ZeroXBufWr.html | 241 ++ Help/attachments/DXMix/sliding_ex_1.png | Bin 0 -> 11560 bytes Help/attachments/DXMix/sliding_ex_2.png | Bin 0 -> 12265 bytes Help/attachments/DXMix/sliding_ex_3.png | Bin 0 -> 11285 bytes Help/attachments/DXMix/sliding_ex_4.png | Bin 0 -> 11818 bytes Help/attachments/DXMix/sliding_ex_5.png | Bin 0 -> 10989 bytes Help/attachments/DXMix/sliding_ex_6.png | Bin 0 -> 10343 bytes .../attachments/Idev suite/XIdev_scheme_3.png | Bin 0 -> 152759 bytes Help/attachments/PSPdiv/PSPdiv_graph_1.png | Bin 0 -> 68104 bytes Help/attachments/PbindFx/PbindFx_graph_1.png | Bin 0 -> 170908 bytes Help/attachments/PbindFx/PbindFx_graph_2a.png | Bin 0 -> 127504 bytes Help/attachments/PbindFx/PbindFx_graph_2b.png | Bin 0 -> 127450 bytes Help/attachments/PbindFx/PbindFx_graph_3a.png | Bin 0 -> 135925 bytes Help/attachments/PbindFx/PbindFx_graph_3b.png | Bin 0 -> 74201 bytes Help/attachments/PbindFx/PbindFx_graph_4a.png | Bin 0 -> 254391 bytes Help/attachments/PbindFx/PbindFx_graph_4b.png | Bin 0 -> 126805 bytes Help/attachments/PbindFx/PbindFx_graph_4c.png | Bin 0 -> 33591 bytes .../fold_examples.png | Bin 0 -> 100666 bytes Help/attachments/VarGui/main_buttons.png | Bin 0 -> 3748 bytes Help/attachments/VarGui/player_1.png | Bin 0 -> 3950 bytes Help/attachments/VarGui/player_10.png | Bin 0 -> 3823 bytes Help/attachments/VarGui/player_2.png | Bin 0 -> 3932 bytes Help/attachments/VarGui/player_3.png | Bin 0 -> 3952 bytes Help/attachments/VarGui/player_4.png | Bin 0 -> 3893 bytes Help/attachments/VarGui/player_5.png | Bin 0 -> 3845 bytes Help/attachments/VarGui/player_6.png | Bin 0 -> 3991 bytes Help/attachments/VarGui/player_7.png | Bin 0 -> 3878 bytes Help/attachments/VarGui/player_8.png | Bin 0 -> 3897 bytes Help/attachments/VarGui/player_9.png | Bin 0 -> 3861 bytes .../Working with HS and HSpar/latency_1.png | Bin 0 -> 7064 bytes .../Working with HS and HSpar/latency_2.png | Bin 0 -> 16792 bytes .../Working with HS and HSpar/latency_3.png | Bin 0 -> 13924 bytes .../Working with HS and HSpar/latency_4.png | Bin 0 -> 9295 bytes .../Working with HS and HSpar/tab_2b.png | Bin 0 -> 37921 bytes Help/attachments/enum/graph.png | Bin 0 -> 6099 bytes Help/enum.html | 358 +++ Help/kitchen studies.html | 1090 +++++++++ Help/miSCellaneous.html | 471 ++++ HelpSource/Classes/Boolean.ext.schelp | 6 + HelpSource/Classes/Buffer.ext.schelp | 16 + HelpSource/Classes/Collection.ext.schelp | 6 + HelpSource/Classes/Color.ext.schelp | 6 + HelpSource/Classes/ControlSpec.ext.schelp | 6 + HelpSource/Classes/DIdev.schelp | 457 ++++ HelpSource/Classes/DXEnvFan.schelp | 727 ++++++ HelpSource/Classes/DXEnvFanOut.schelp | 222 ++ HelpSource/Classes/DXFan.schelp | 327 +++ HelpSource/Classes/DXFanOut.schelp | 273 +++ HelpSource/Classes/DXMix.schelp | 988 ++++++++ HelpSource/Classes/DXMixIn.schelp | 219 ++ HelpSource/Classes/Dictionary.ext.schelp | 6 + HelpSource/Classes/EZSlider.ext.schelp | 7 + HelpSource/Classes/Event.ext.schelp | 22 + HelpSource/Classes/EventShortcuts.schelp | 306 +++ .../Classes/EventStreamPlayer.ext.schelp | 5 + HelpSource/Classes/FFT.ext.schelp | 6 + HelpSource/Classes/Fb1.schelp | 1652 +++++++++++++ HelpSource/Classes/Fb1_Duffing.schelp | 320 +++ HelpSource/Classes/Fb1_Hopf.schelp | 334 +++ HelpSource/Classes/Fb1_HopfA.schelp | 340 +++ HelpSource/Classes/Fb1_HopfAFDC.schelp | 396 +++ HelpSource/Classes/Fb1_Lorenz.schelp | 335 +++ HelpSource/Classes/Fb1_MSD.schelp | 313 +++ HelpSource/Classes/Fb1_ODE.schelp | 1151 +++++++++ HelpSource/Classes/Fb1_ODEdef.schelp | 475 ++++ HelpSource/Classes/Fb1_ODEintdef.schelp | 186 ++ HelpSource/Classes/Fb1_SD.schelp | 304 +++ HelpSource/Classes/Fb1_VanDerPol.schelp | 322 +++ HelpSource/Classes/Float.ext.schelp | 6 + HelpSource/Classes/Function.ext.schelp | 8 + HelpSource/Classes/FunctionDef.ext.schelp | 4 + HelpSource/Classes/GFIS.schelp | 556 +++++ HelpSource/Classes/HS.schelp | 248 ++ HelpSource/Classes/HSpar.schelp | 97 + .../Classes/IdentityDictionary.ext.schelp | 6 + HelpSource/Classes/Integer.ext.schelp | 36 + HelpSource/Classes/MemoRoutine.schelp | 227 ++ HelpSource/Classes/Method.ext.schelp | 8 + HelpSource/Classes/Nil.ext.schelp | 6 + HelpSource/Classes/Node.ext.schelp | 6 + HelpSource/Classes/Object.ext.schelp | 32 + HelpSource/Classes/PHS.schelp | 196 ++ HelpSource/Classes/PHSpar.schelp | 415 ++++ HelpSource/Classes/PHSparPlayer.schelp | 291 +++ HelpSource/Classes/PHSparUse.schelp | 178 ++ HelpSource/Classes/PHSplayer.schelp | 104 + HelpSource/Classes/PHSuse.schelp | 127 + HelpSource/Classes/PHSusePlayer.schelp | 104 + HelpSource/Classes/PIdev.schelp | 346 +++ HelpSource/Classes/PL.schelp | 144 ++ HelpSource/Classes/PLIdev.schelp | 378 +++ HelpSource/Classes/PLbeta.schelp | 114 + HelpSource/Classes/PLbindef.schelp | 423 ++++ HelpSource/Classes/PLbindefEnvironment.schelp | 82 + HelpSource/Classes/PLbindefPar.schelp | 672 +++++ .../Classes/PLbindefParEnvironment.schelp | 98 + HelpSource/Classes/PLbrown.schelp | 88 + HelpSource/Classes/PLcauchy.schelp | 86 + HelpSource/Classes/PLexprand.schelp | 85 + HelpSource/Classes/PLgauss.schelp | 86 + HelpSource/Classes/PLgbrown.schelp | 97 + HelpSource/Classes/PLgeom.schelp | 85 + HelpSource/Classes/PLhprand.schelp | 90 + HelpSource/Classes/PLlprand.schelp | 91 + HelpSource/Classes/PLmeanrand.schelp | 87 + HelpSource/Classes/PLn.schelp | 219 ++ HelpSource/Classes/PLnaryFunc.schelp | 90 + HelpSource/Classes/PLnaryop.schelp | 82 + HelpSource/Classes/PLpoisson.schelp | 75 + HelpSource/Classes/PLrand.schelp | 139 ++ HelpSource/Classes/PLseq.schelp | 137 ++ HelpSource/Classes/PLser.schelp | 115 + HelpSource/Classes/PLseries.schelp | 92 + HelpSource/Classes/PLshuf.schelp | 138 ++ HelpSource/Classes/PLshufn.schelp | 145 ++ HelpSource/Classes/PLslide.schelp | 158 ++ HelpSource/Classes/PLswitch.schelp | 162 ++ HelpSource/Classes/PLswitch1.schelp | 163 ++ HelpSource/Classes/PLtuple.schelp | 94 + HelpSource/Classes/PLwalk.schelp | 186 ++ HelpSource/Classes/PLwhite.schelp | 84 + HelpSource/Classes/PLwrand.schelp | 103 + HelpSource/Classes/PLxrand.schelp | 150 ++ HelpSource/Classes/PS.schelp | 251 ++ HelpSource/Classes/PSPdiv.ext.schelp | 4 + HelpSource/Classes/PSPdiv.schelp | 524 ++++ HelpSource/Classes/PSVdif.schelp | 52 + HelpSource/Classes/PSVdif_i.schelp | 53 + HelpSource/Classes/PSVdif_o.schelp | 53 + HelpSource/Classes/PSVdif_oi.schelp | 53 + HelpSource/Classes/PSVop.schelp | 73 + HelpSource/Classes/PSVop_i.schelp | 72 + HelpSource/Classes/PSVop_o.schelp | 75 + HelpSource/Classes/PSVop_oi.schelp | 74 + HelpSource/Classes/PSVsect.schelp | 52 + HelpSource/Classes/PSVsect_i.schelp | 52 + HelpSource/Classes/PSVsect_o.schelp | 53 + HelpSource/Classes/PSVsect_oi.schelp | 53 + HelpSource/Classes/PSVsymdif.schelp | 52 + HelpSource/Classes/PSVsymdif_i.schelp | 53 + HelpSource/Classes/PSVsymdif_o.schelp | 54 + HelpSource/Classes/PSVsymdif_oi.schelp | 53 + HelpSource/Classes/PSVunion.schelp | 53 + HelpSource/Classes/PSVunion_i.schelp | 52 + HelpSource/Classes/PSVunion_o.schelp | 53 + HelpSource/Classes/PSVunion_oi.schelp | 53 + HelpSource/Classes/PSdup.schelp | 172 ++ HelpSource/Classes/PSloop.schelp | 681 ++++++ HelpSource/Classes/PSrecur.schelp | 117 + HelpSource/Classes/PV_BinGap.schelp | 103 + HelpSource/Classes/PV_BinRange.schelp | 103 + HelpSource/Classes/Pattern.ext.schelp | 24 + HelpSource/Classes/PbindFx.schelp | 2096 ++++++++++++++++ HelpSource/Classes/PlaceAll.schelp | 85 + HelpSource/Classes/Platform.ext.schelp | 12 + HelpSource/Classes/PmonoPar.schelp | 156 ++ HelpSource/Classes/PpolyPar.schelp | 500 ++++ HelpSource/Classes/Pshufn.schelp | 51 + HelpSource/Classes/Psieve.schelp | 19 + HelpSource/Classes/PsymNilSafe.schelp | 55 + .../Classes/SequenceableCollection.ext.schelp | 195 ++ HelpSource/Classes/Set.ext.schelp | 5 + HelpSource/Classes/Sieve.schelp | 949 +++++++ HelpSource/Classes/SimpleNumber.ext.schelp | 5 + HelpSource/Classes/SkipJack.ext.schelp | 5 + HelpSource/Classes/SmoothClipQ.schelp | 65 + HelpSource/Classes/SmoothClipS.schelp | 65 + HelpSource/Classes/SmoothFoldQ.schelp | 72 + HelpSource/Classes/SmoothFoldQ2.schelp | 82 + HelpSource/Classes/SmoothFoldS.schelp | 72 + HelpSource/Classes/SmoothFoldS2.schelp | 81 + HelpSource/Classes/Stream.ext.schelp | 10 + HelpSource/Classes/String.ext.schelp | 26 + HelpSource/Classes/Symbol.ext.schelp | 212 ++ HelpSource/Classes/Synth.ext.schelp | 7 + HelpSource/Classes/TZeroXBufRd.schelp | 718 ++++++ HelpSource/Classes/TempoClock.ext.schelp | 4 + HelpSource/Classes/Thread.ext.schelp | 4 + HelpSource/Classes/UGen.ext.schelp | 5 + HelpSource/Classes/VarGui.schelp | 1677 +++++++++++++ HelpSource/Classes/ZeroXBufRd.schelp | 861 +++++++ HelpSource/Classes/ZeroXBufWr.schelp | 218 ++ .../attachments/DXMix/sliding_ex_1.png | Bin 0 -> 11560 bytes .../attachments/DXMix/sliding_ex_2.png | Bin 0 -> 12265 bytes .../attachments/DXMix/sliding_ex_3.png | Bin 0 -> 11285 bytes .../attachments/DXMix/sliding_ex_4.png | Bin 0 -> 11818 bytes .../attachments/DXMix/sliding_ex_5.png | Bin 0 -> 10989 bytes .../attachments/DXMix/sliding_ex_6.png | Bin 0 -> 10343 bytes .../attachments/PSPdiv/PSPdiv_graph_1.png | Bin 0 -> 35624 bytes .../attachments/PbindFx/PbindFx_graph_1.png | Bin 0 -> 26609 bytes .../attachments/PbindFx/PbindFx_graph_2a.png | Bin 0 -> 31501 bytes .../attachments/PbindFx/PbindFx_graph_2b.png | Bin 0 -> 30973 bytes .../attachments/PbindFx/PbindFx_graph_3a.png | Bin 0 -> 59340 bytes .../attachments/PbindFx/PbindFx_graph_3b.png | Bin 0 -> 32730 bytes .../attachments/PbindFx/PbindFx_graph_4a.png | Bin 0 -> 47916 bytes .../attachments/PbindFx/PbindFx_graph_4b.png | Bin 0 -> 24813 bytes .../attachments/PbindFx/PbindFx_graph_4c.png | Bin 0 -> 33591 bytes .../attachments/VarGui/main_buttons.png | Bin 0 -> 3748 bytes .../Classes/attachments/VarGui/player_1.png | Bin 0 -> 3950 bytes .../Classes/attachments/VarGui/player_10.png | Bin 0 -> 3823 bytes .../Classes/attachments/VarGui/player_2.png | Bin 0 -> 3932 bytes .../Classes/attachments/VarGui/player_3.png | Bin 0 -> 3952 bytes .../Classes/attachments/VarGui/player_4.png | Bin 0 -> 3893 bytes .../Classes/attachments/VarGui/player_5.png | Bin 0 -> 3845 bytes .../Classes/attachments/VarGui/player_6.png | Bin 0 -> 3991 bytes .../Classes/attachments/VarGui/player_7.png | Bin 0 -> 3878 bytes .../Classes/attachments/VarGui/player_8.png | Bin 0 -> 3897 bytes .../Classes/attachments/VarGui/player_9.png | Bin 0 -> 3861 bytes .../Guides/Guide_to_HS_and_HSpar.schelp | 120 + .../Introduction_to_miSCellaneous.schelp | 582 +++++ .../Guide_to_HS_and_HSpar/latencyCorr_1b.png | Bin 0 -> 2838 bytes .../Guide_to_HS_and_HSpar/latencyCorr_2b.png | Bin 0 -> 14429 bytes .../Guide_to_HS_and_HSpar/latencyCorr_3b.png | Bin 0 -> 8620 bytes .../Guide_to_HS_and_HSpar/latencyCorr_4b.png | Bin 0 -> 4942 bytes .../Guide_to_HS_and_HSpar/tab_2b.png | Bin 0 -> 37921 bytes HelpSource/Overviews/miSCellaneous.schelp | 494 ++++ .../Tutorials/Buffer_Granulation.schelp | 1695 +++++++++++++ HelpSource/Tutorials/DX_suite.schelp | 156 ++ .../Event_patterns_and_Functions.schelp | 320 +++ .../Tutorials/Event_patterns_and_LFOs.schelp | 572 +++++ .../Event_patterns_and_array_args.schelp | 678 +++++ HelpSource/Tutorials/HS_with_VarGui.schelp | 360 +++ HelpSource/Tutorials/Idev_suite.schelp | 26 + HelpSource/Tutorials/Live_Granulation.schelp | 900 +++++++ .../Other_event_and_pattern_shortcuts.schelp | 221 ++ .../PLx_and_live_coding_with_Strings.schelp | 773 ++++++ HelpSource/Tutorials/PLx_suite.schelp | 577 +++++ .../Tutorials/PSx_stream_patterns.schelp | 69 + .../Sieves_and_Psieve_patterns.schelp | 1347 ++++++++++ .../Smooth_Clipping_and_Folding.schelp | 207 ++ .../Tutorials/VarGui_shortcut_builds.schelp | 907 +++++++ .../attachments/Idev_suite/Idev_scheme_3.png | Bin 0 -> 152759 bytes .../fold_examples.png | Bin 0 -> 100666 bytes .../Tutorials/attachments/enum/graph.png | Bin 0 -> 6099 bytes HelpSource/Tutorials/enum.schelp | 323 +++ HelpSource/Tutorials/kitchen_studies.schelp | 1078 ++++++++ LICENSE.txt | 339 +++ README.txt | 448 ++++ Sounds/kitchen_sounds_1.wav | Bin 0 -> 461824 bytes miSCellaneous_lib.quark | 13 + 475 files changed, 100559 insertions(+) create mode 100644 .gitattributes.txt create mode 100644 .gitignore.txt create mode 100644 Classes/DX/AbstractDX.sc create mode 100644 Classes/DX/extUGen.sc create mode 100644 Classes/Enumeration/extInteger.sc create mode 100644 Classes/FFT/PV_UGens.sc create mode 100644 Classes/FFT/extFFT.sc create mode 100644 Classes/FFT/extSequenceableCollection.sc create mode 100755 Classes/HS/HelpSynth.sc create mode 100755 Classes/HS/HelpSynthPar.sc create mode 100644 Classes/HS/PHelpSynth.sc create mode 100644 Classes/HS/PHelpSynthPar.sc create mode 100644 Classes/HS/PHelpSynthParPlayer.sc create mode 100644 Classes/HS/PHelpSynthParUse.sc create mode 100644 Classes/HS/PHelpSynthPlayer.sc create mode 100644 Classes/HS/PHelpSynthUse.sc create mode 100644 Classes/HS/PHelpSynthUsePlayer.sc create mode 100644 Classes/HS/extHelpSynth.sc create mode 100644 Classes/HS/extObject.sc create mode 100644 Classes/HS/extSequenceableCollection.sc create mode 100644 Classes/HS/extSynth.sc create mode 100644 Classes/HS/extTempoClock.sc create mode 100644 Classes/HS/extThread.sc create mode 100644 Classes/Nonlinear/Fb1.sc create mode 100644 Classes/Nonlinear/Fb1_ODE.sc create mode 100755 Classes/Nonlinear/Fb1_ODEdef.sc create mode 100644 Classes/Nonlinear/Fb1_ODEintdef.sc create mode 100644 Classes/Nonlinear/GFIS.sc create mode 100644 Classes/Nonlinear/extObject.sc create mode 100644 Classes/Nonlinear/extSequenceableCollection.sc create mode 100644 Classes/Nonlinear/extUGen.sc create mode 100644 Classes/Other/DIdev.sc create mode 100644 Classes/Other/extPlatform.sc create mode 100644 Classes/Other/extUGen.sc create mode 100644 Classes/Patterns/AddEventTypes_PbindFx.sc create mode 100644 Classes/Patterns/EventShortcuts.sc create mode 100644 Classes/Patterns/MemoRoutine.sc create mode 100755 Classes/Patterns/OtherPatterns.sc create mode 100644 Classes/Patterns/PIdev.sc create mode 100755 Classes/Patterns/PL.sc create mode 100644 Classes/Patterns/PL_ListProxy.sc create mode 100755 Classes/Patterns/PLbindef.sc create mode 100644 Classes/Patterns/PLbindefPar.sc create mode 100755 Classes/Patterns/PS.sc create mode 100755 Classes/Patterns/PSPdiv.sc create mode 100644 Classes/Patterns/PbindFx.sc create mode 100644 Classes/Patterns/Pclutch_PbindFx.sc create mode 100644 Classes/Patterns/extDictionary.sc create mode 100755 Classes/Patterns/extEvent.sc create mode 100644 Classes/Patterns/extIdentityDictionary.sc create mode 100644 Classes/Patterns/extObject.sc create mode 100755 Classes/Patterns/extObject_2.sc create mode 100644 Classes/Patterns/extPattern.sc create mode 100644 Classes/Patterns/extPbindFx_1.sc create mode 100644 Classes/Patterns/extPbindFx_2.sc create mode 100644 Classes/Patterns/extPbindFx_3.sc create mode 100644 Classes/Patterns/extPbindFx_4.sc create mode 100644 Classes/Patterns/extSequenceableCollection.sc create mode 100644 Classes/Patterns/extStream.sc create mode 100644 Classes/Patterns/extSymbol.sc create mode 100755 Classes/Sieves/Psieve.sc create mode 100755 Classes/Sieves/Sieve.sc create mode 100644 Classes/Sieves/lcmExtensions.sc create mode 100644 Classes/Sieves/periods.sc create mode 100755 Classes/Sieves/streamifySieveItems.sc create mode 100755 Classes/Sieves/toSieve.sc create mode 100644 Classes/VarGui/SimpleInitError.sc create mode 100644 Classes/VarGui/SimpleInputError.sc create mode 100644 Classes/VarGui/VarGui.sc create mode 100755 Classes/VarGui/VarGuiPlayerSection.sc create mode 100644 Classes/VarGui/extBoolean.sc create mode 100644 Classes/VarGui/extCollection.sc create mode 100644 Classes/VarGui/extColor.sc create mode 100644 Classes/VarGui/extControlSpec.sc create mode 100644 Classes/VarGui/extDictionary.sc create mode 100644 Classes/VarGui/extEZSlider.sc create mode 100644 Classes/VarGui/extFloat.sc create mode 100644 Classes/VarGui/extFunction.sc create mode 100644 Classes/VarGui/extFunctionDef.sc create mode 100644 Classes/VarGui/extInteger_1.sc create mode 100644 Classes/VarGui/extInteger_2.sc create mode 100644 Classes/VarGui/extInteger_3.sc create mode 100644 Classes/VarGui/extNil.sc create mode 100644 Classes/VarGui/extNode.sc create mode 100644 Classes/VarGui/extObject.sc create mode 100644 Classes/VarGui/extOther.sc create mode 100644 Classes/VarGui/extPauseStream.sc create mode 100644 Classes/VarGui/extSequenceableCollection_1.sc create mode 100644 Classes/VarGui/extSequenceableCollection_2.sc create mode 100644 Classes/VarGui/extSimpleNumber.sc create mode 100644 Classes/VarGui/extString_1.sc create mode 100644 Classes/VarGui/extString_2.sc create mode 100644 Classes/VarGui/extSymbol_1.sc create mode 100644 Classes/VarGui/extSymbol_2.sc create mode 100644 Classes/VarGui/extSynth.sc create mode 100644 Classes/VarGui/extVarGuiPlayerSection.sc create mode 100644 Classes/VarGui/extVarGui_1.sc create mode 100644 Classes/VarGui/extVarGui_2.sc create mode 100644 Classes/VarGui/extVarGui_3.sc create mode 100644 Classes/VarGui/extVarGui_4.sc create mode 100644 Classes/VarGui/extVarGui_5.sc create mode 100644 Classes/VarGui/extVarGui_6.sc create mode 100755 Classes/WaveFolding/SmoothClip.sc create mode 100755 Classes/WaveFolding/SmoothFold.sc create mode 100644 Classes/ZeroX/TZeroXBufRd.sc create mode 100644 Classes/ZeroX/ZeroXBufRd.sc create mode 100644 Classes/ZeroX/ZeroXBufWr.sc create mode 100644 Classes/ZeroX/extBuffer.sc create mode 100755 Help/Buffer Granulation.html create mode 100755 Help/DIdev.html create mode 100755 Help/DX suite.html create mode 100755 Help/DXEnvFan.html create mode 100755 Help/DXEnvFanOut.html create mode 100755 Help/DXFan.html create mode 100755 Help/DXFanOut.html create mode 100755 Help/DXMix.html create mode 100755 Help/DXMixIn.html create mode 100755 Help/Event patterns and Functions.html create mode 100644 Help/Event patterns and LFOs.html create mode 100644 Help/Event patterns and array args.html create mode 100644 Help/EventShortcuts.html create mode 100755 Help/Fb1.html create mode 100755 Help/Fb1_Duffing.html create mode 100755 Help/Fb1_Hopf.html create mode 100755 Help/Fb1_HopfA.html create mode 100755 Help/Fb1_HopfAFDC.html create mode 100755 Help/Fb1_Lorenz.html create mode 100755 Help/Fb1_MSD.html create mode 100755 Help/Fb1_ODE.html create mode 100755 Help/Fb1_ODEdef.html create mode 100755 Help/Fb1_ODEintdef.html create mode 100755 Help/Fb1_SD.html create mode 100755 Help/Fb1_VanDerPol.html create mode 100755 Help/GFIS.html create mode 100644 Help/HS with VarGui.html create mode 100755 Help/HS.html create mode 100755 Help/HSpar.html create mode 100755 Help/Idev suite.html create mode 100755 Help/Introduction to miSCellaneous.html create mode 100755 Help/Live Granulation.html create mode 100755 Help/MemoRoutine.html create mode 100644 Help/Other event and pattern shortcuts.html create mode 100755 Help/PHS.html create mode 100755 Help/PHSpar.html create mode 100755 Help/PHSparPlayer.html create mode 100644 Help/PHSparUse.html create mode 100755 Help/PHSplayer.html create mode 100755 Help/PHSuse.html create mode 100755 Help/PHSusePlayer.html create mode 100755 Help/PIdev.html create mode 100755 Help/PL.html create mode 100755 Help/PLIdev.html create mode 100755 Help/PLbeta.html create mode 100755 Help/PLbindef.html create mode 100755 Help/PLbindefEnvironment.html create mode 100755 Help/PLbindefPar.html create mode 100755 Help/PLbindefParEnvironment.html create mode 100755 Help/PLbrown.html create mode 100755 Help/PLcauchy.html create mode 100755 Help/PLexprand.html create mode 100755 Help/PLgauss.html create mode 100755 Help/PLgbrown.html create mode 100755 Help/PLgeom.html create mode 100755 Help/PLhprand.html create mode 100755 Help/PLlprand.html create mode 100755 Help/PLmeanrand.html create mode 100755 Help/PLn.html create mode 100755 Help/PLnaryFunc.html create mode 100755 Help/PLnaryop.html create mode 100755 Help/PLpoisson.html create mode 100755 Help/PLrand.html create mode 100755 Help/PLseq.html create mode 100755 Help/PLser.html create mode 100755 Help/PLseries.html create mode 100755 Help/PLshuf.html create mode 100755 Help/PLshufn.html create mode 100755 Help/PLslide.html create mode 100755 Help/PLswitch.html create mode 100755 Help/PLswitch1.html create mode 100755 Help/PLtuple.html create mode 100755 Help/PLwalk.html create mode 100755 Help/PLwhite.html create mode 100755 Help/PLwrand.html create mode 100644 Help/PLx and live coding with Strings.html create mode 100755 Help/PLx suite.html create mode 100755 Help/PLxrand.html create mode 100755 Help/PS.html create mode 100755 Help/PSPdiv.html create mode 100755 Help/PSVdif.html create mode 100755 Help/PSVdif_i.html create mode 100755 Help/PSVdif_o.html create mode 100755 Help/PSVdif_oi.html create mode 100755 Help/PSVop.html create mode 100755 Help/PSVop_i.html create mode 100755 Help/PSVop_o.html create mode 100755 Help/PSVop_oi.html create mode 100755 Help/PSVsect.html create mode 100755 Help/PSVsect_i.html create mode 100755 Help/PSVsect_o.html create mode 100755 Help/PSVsect_oi.html create mode 100755 Help/PSVsymdif.html create mode 100755 Help/PSVsymdif_i.html create mode 100755 Help/PSVsymdif_o.html create mode 100755 Help/PSVsymdif_oi.html create mode 100755 Help/PSVunion.html create mode 100755 Help/PSVunion_i.html create mode 100755 Help/PSVunion_o.html create mode 100755 Help/PSVunion_oi.html create mode 100755 Help/PSdup.html create mode 100755 Help/PSloop.html create mode 100755 Help/PSrecur.html create mode 100755 Help/PSx stream patterns.html create mode 100755 Help/PV_BinGap.html create mode 100755 Help/PV_BinRange.html create mode 100755 Help/PbindFx.html create mode 100755 Help/PlaceAll.html create mode 100755 Help/PmonoPar.html create mode 100755 Help/PpolyPar.html create mode 100755 Help/Pshufn.html create mode 100755 Help/Psieve.html create mode 100755 Help/PsymNilSafe.html create mode 100755 Help/Sieve.html create mode 100755 Help/Sieves and Psieve patterns.html create mode 100755 Help/Smooth Clipping and Folding.html create mode 100755 Help/SmoothClipQ.html create mode 100755 Help/SmoothClipS.html create mode 100755 Help/SmoothFoldQ.html create mode 100755 Help/SmoothFoldQ2.html create mode 100755 Help/SmoothFoldS.html create mode 100755 Help/SmoothFoldS2.html create mode 100755 Help/TZeroXBufRd.html create mode 100644 Help/VarGui shortcut builds.html create mode 100755 Help/VarGui.html create mode 100644 Help/Working with HS and HSpar.html create mode 100755 Help/ZeroXBufRd.html create mode 100755 Help/ZeroXBufWr.html create mode 100644 Help/attachments/DXMix/sliding_ex_1.png create mode 100644 Help/attachments/DXMix/sliding_ex_2.png create mode 100644 Help/attachments/DXMix/sliding_ex_3.png create mode 100644 Help/attachments/DXMix/sliding_ex_4.png create mode 100644 Help/attachments/DXMix/sliding_ex_5.png create mode 100644 Help/attachments/DXMix/sliding_ex_6.png create mode 100644 Help/attachments/Idev suite/XIdev_scheme_3.png create mode 100755 Help/attachments/PSPdiv/PSPdiv_graph_1.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_1.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_2a.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_2b.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_3a.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_3b.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_4a.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_4b.png create mode 100644 Help/attachments/PbindFx/PbindFx_graph_4c.png create mode 100644 Help/attachments/Smooth Clipping and Folding/fold_examples.png create mode 100644 Help/attachments/VarGui/main_buttons.png create mode 100644 Help/attachments/VarGui/player_1.png create mode 100644 Help/attachments/VarGui/player_10.png create mode 100644 Help/attachments/VarGui/player_2.png create mode 100644 Help/attachments/VarGui/player_3.png create mode 100644 Help/attachments/VarGui/player_4.png create mode 100644 Help/attachments/VarGui/player_5.png create mode 100644 Help/attachments/VarGui/player_6.png create mode 100644 Help/attachments/VarGui/player_7.png create mode 100644 Help/attachments/VarGui/player_8.png create mode 100644 Help/attachments/VarGui/player_9.png create mode 100644 Help/attachments/Working with HS and HSpar/latency_1.png create mode 100644 Help/attachments/Working with HS and HSpar/latency_2.png create mode 100644 Help/attachments/Working with HS and HSpar/latency_3.png create mode 100644 Help/attachments/Working with HS and HSpar/latency_4.png create mode 100644 Help/attachments/Working with HS and HSpar/tab_2b.png create mode 100644 Help/attachments/enum/graph.png create mode 100644 Help/enum.html create mode 100755 Help/kitchen studies.html create mode 100644 Help/miSCellaneous.html create mode 100644 HelpSource/Classes/Boolean.ext.schelp create mode 100755 HelpSource/Classes/Buffer.ext.schelp create mode 100644 HelpSource/Classes/Collection.ext.schelp create mode 100644 HelpSource/Classes/Color.ext.schelp create mode 100644 HelpSource/Classes/ControlSpec.ext.schelp create mode 100755 HelpSource/Classes/DIdev.schelp create mode 100644 HelpSource/Classes/DXEnvFan.schelp create mode 100644 HelpSource/Classes/DXEnvFanOut.schelp create mode 100644 HelpSource/Classes/DXFan.schelp create mode 100644 HelpSource/Classes/DXFanOut.schelp create mode 100644 HelpSource/Classes/DXMix.schelp create mode 100644 HelpSource/Classes/DXMixIn.schelp create mode 100644 HelpSource/Classes/Dictionary.ext.schelp create mode 100644 HelpSource/Classes/EZSlider.ext.schelp create mode 100644 HelpSource/Classes/Event.ext.schelp create mode 100644 HelpSource/Classes/EventShortcuts.schelp create mode 100644 HelpSource/Classes/EventStreamPlayer.ext.schelp create mode 100644 HelpSource/Classes/FFT.ext.schelp create mode 100755 HelpSource/Classes/Fb1.schelp create mode 100755 HelpSource/Classes/Fb1_Duffing.schelp create mode 100755 HelpSource/Classes/Fb1_Hopf.schelp create mode 100755 HelpSource/Classes/Fb1_HopfA.schelp create mode 100755 HelpSource/Classes/Fb1_HopfAFDC.schelp create mode 100755 HelpSource/Classes/Fb1_Lorenz.schelp create mode 100755 HelpSource/Classes/Fb1_MSD.schelp create mode 100755 HelpSource/Classes/Fb1_ODE.schelp create mode 100755 HelpSource/Classes/Fb1_ODEdef.schelp create mode 100755 HelpSource/Classes/Fb1_ODEintdef.schelp create mode 100755 HelpSource/Classes/Fb1_SD.schelp create mode 100755 HelpSource/Classes/Fb1_VanDerPol.schelp create mode 100644 HelpSource/Classes/Float.ext.schelp create mode 100644 HelpSource/Classes/Function.ext.schelp create mode 100644 HelpSource/Classes/FunctionDef.ext.schelp create mode 100755 HelpSource/Classes/GFIS.schelp create mode 100644 HelpSource/Classes/HS.schelp create mode 100644 HelpSource/Classes/HSpar.schelp create mode 100644 HelpSource/Classes/IdentityDictionary.ext.schelp create mode 100644 HelpSource/Classes/Integer.ext.schelp create mode 100644 HelpSource/Classes/MemoRoutine.schelp create mode 100644 HelpSource/Classes/Method.ext.schelp create mode 100644 HelpSource/Classes/Nil.ext.schelp create mode 100644 HelpSource/Classes/Node.ext.schelp create mode 100644 HelpSource/Classes/Object.ext.schelp create mode 100644 HelpSource/Classes/PHS.schelp create mode 100644 HelpSource/Classes/PHSpar.schelp create mode 100755 HelpSource/Classes/PHSparPlayer.schelp create mode 100644 HelpSource/Classes/PHSparUse.schelp create mode 100755 HelpSource/Classes/PHSplayer.schelp create mode 100644 HelpSource/Classes/PHSuse.schelp create mode 100755 HelpSource/Classes/PHSusePlayer.schelp create mode 100755 HelpSource/Classes/PIdev.schelp create mode 100644 HelpSource/Classes/PL.schelp create mode 100755 HelpSource/Classes/PLIdev.schelp create mode 100644 HelpSource/Classes/PLbeta.schelp create mode 100755 HelpSource/Classes/PLbindef.schelp create mode 100644 HelpSource/Classes/PLbindefEnvironment.schelp create mode 100755 HelpSource/Classes/PLbindefPar.schelp create mode 100644 HelpSource/Classes/PLbindefParEnvironment.schelp create mode 100644 HelpSource/Classes/PLbrown.schelp create mode 100644 HelpSource/Classes/PLcauchy.schelp create mode 100644 HelpSource/Classes/PLexprand.schelp create mode 100644 HelpSource/Classes/PLgauss.schelp create mode 100644 HelpSource/Classes/PLgbrown.schelp create mode 100644 HelpSource/Classes/PLgeom.schelp create mode 100644 HelpSource/Classes/PLhprand.schelp create mode 100644 HelpSource/Classes/PLlprand.schelp create mode 100644 HelpSource/Classes/PLmeanrand.schelp create mode 100644 HelpSource/Classes/PLn.schelp create mode 100755 HelpSource/Classes/PLnaryFunc.schelp create mode 100755 HelpSource/Classes/PLnaryop.schelp create mode 100644 HelpSource/Classes/PLpoisson.schelp create mode 100644 HelpSource/Classes/PLrand.schelp create mode 100755 HelpSource/Classes/PLseq.schelp create mode 100644 HelpSource/Classes/PLser.schelp create mode 100644 HelpSource/Classes/PLseries.schelp create mode 100644 HelpSource/Classes/PLshuf.schelp create mode 100644 HelpSource/Classes/PLshufn.schelp create mode 100644 HelpSource/Classes/PLslide.schelp create mode 100644 HelpSource/Classes/PLswitch.schelp create mode 100644 HelpSource/Classes/PLswitch1.schelp create mode 100644 HelpSource/Classes/PLtuple.schelp create mode 100644 HelpSource/Classes/PLwalk.schelp create mode 100644 HelpSource/Classes/PLwhite.schelp create mode 100644 HelpSource/Classes/PLwrand.schelp create mode 100644 HelpSource/Classes/PLxrand.schelp create mode 100644 HelpSource/Classes/PS.schelp create mode 100644 HelpSource/Classes/PSPdiv.ext.schelp create mode 100755 HelpSource/Classes/PSPdiv.schelp create mode 100644 HelpSource/Classes/PSVdif.schelp create mode 100644 HelpSource/Classes/PSVdif_i.schelp create mode 100644 HelpSource/Classes/PSVdif_o.schelp create mode 100644 HelpSource/Classes/PSVdif_oi.schelp create mode 100644 HelpSource/Classes/PSVop.schelp create mode 100644 HelpSource/Classes/PSVop_i.schelp create mode 100644 HelpSource/Classes/PSVop_o.schelp create mode 100644 HelpSource/Classes/PSVop_oi.schelp create mode 100644 HelpSource/Classes/PSVsect.schelp create mode 100644 HelpSource/Classes/PSVsect_i.schelp create mode 100644 HelpSource/Classes/PSVsect_o.schelp create mode 100644 HelpSource/Classes/PSVsect_oi.schelp create mode 100644 HelpSource/Classes/PSVsymdif.schelp create mode 100644 HelpSource/Classes/PSVsymdif_i.schelp create mode 100644 HelpSource/Classes/PSVsymdif_o.schelp create mode 100644 HelpSource/Classes/PSVsymdif_oi.schelp create mode 100644 HelpSource/Classes/PSVunion.schelp create mode 100644 HelpSource/Classes/PSVunion_i.schelp create mode 100644 HelpSource/Classes/PSVunion_o.schelp create mode 100644 HelpSource/Classes/PSVunion_oi.schelp create mode 100644 HelpSource/Classes/PSdup.schelp create mode 100644 HelpSource/Classes/PSloop.schelp create mode 100644 HelpSource/Classes/PSrecur.schelp create mode 100755 HelpSource/Classes/PV_BinGap.schelp create mode 100755 HelpSource/Classes/PV_BinRange.schelp create mode 100644 HelpSource/Classes/Pattern.ext.schelp create mode 100755 HelpSource/Classes/PbindFx.schelp create mode 100644 HelpSource/Classes/PlaceAll.schelp create mode 100755 HelpSource/Classes/Platform.ext.schelp create mode 100644 HelpSource/Classes/PmonoPar.schelp create mode 100644 HelpSource/Classes/PpolyPar.schelp create mode 100644 HelpSource/Classes/Pshufn.schelp create mode 100644 HelpSource/Classes/Psieve.schelp create mode 100644 HelpSource/Classes/PsymNilSafe.schelp create mode 100755 HelpSource/Classes/SequenceableCollection.ext.schelp create mode 100755 HelpSource/Classes/Set.ext.schelp create mode 100644 HelpSource/Classes/Sieve.schelp create mode 100644 HelpSource/Classes/SimpleNumber.ext.schelp create mode 100644 HelpSource/Classes/SkipJack.ext.schelp create mode 100644 HelpSource/Classes/SmoothClipQ.schelp create mode 100644 HelpSource/Classes/SmoothClipS.schelp create mode 100644 HelpSource/Classes/SmoothFoldQ.schelp create mode 100644 HelpSource/Classes/SmoothFoldQ2.schelp create mode 100644 HelpSource/Classes/SmoothFoldS.schelp create mode 100644 HelpSource/Classes/SmoothFoldS2.schelp create mode 100644 HelpSource/Classes/Stream.ext.schelp create mode 100644 HelpSource/Classes/String.ext.schelp create mode 100644 HelpSource/Classes/Symbol.ext.schelp create mode 100644 HelpSource/Classes/Synth.ext.schelp create mode 100755 HelpSource/Classes/TZeroXBufRd.schelp create mode 100644 HelpSource/Classes/TempoClock.ext.schelp create mode 100644 HelpSource/Classes/Thread.ext.schelp create mode 100755 HelpSource/Classes/UGen.ext.schelp create mode 100755 HelpSource/Classes/VarGui.schelp create mode 100755 HelpSource/Classes/ZeroXBufRd.schelp create mode 100755 HelpSource/Classes/ZeroXBufWr.schelp create mode 100644 HelpSource/Classes/attachments/DXMix/sliding_ex_1.png create mode 100644 HelpSource/Classes/attachments/DXMix/sliding_ex_2.png create mode 100644 HelpSource/Classes/attachments/DXMix/sliding_ex_3.png create mode 100644 HelpSource/Classes/attachments/DXMix/sliding_ex_4.png create mode 100644 HelpSource/Classes/attachments/DXMix/sliding_ex_5.png create mode 100644 HelpSource/Classes/attachments/DXMix/sliding_ex_6.png create mode 100755 HelpSource/Classes/attachments/PSPdiv/PSPdiv_graph_1.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_1.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_2a.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_2b.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_3a.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_3b.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4a.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4b.png create mode 100644 HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4c.png create mode 100644 HelpSource/Classes/attachments/VarGui/main_buttons.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_1.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_10.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_2.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_3.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_4.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_5.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_6.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_7.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_8.png create mode 100644 HelpSource/Classes/attachments/VarGui/player_9.png create mode 100644 HelpSource/Guides/Guide_to_HS_and_HSpar.schelp create mode 100755 HelpSource/Guides/Introduction_to_miSCellaneous.schelp create mode 100644 HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_1b.png create mode 100644 HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_2b.png create mode 100644 HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_3b.png create mode 100644 HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_4b.png create mode 100644 HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/tab_2b.png create mode 100644 HelpSource/Overviews/miSCellaneous.schelp create mode 100755 HelpSource/Tutorials/Buffer_Granulation.schelp create mode 100644 HelpSource/Tutorials/DX_suite.schelp create mode 100644 HelpSource/Tutorials/Event_patterns_and_Functions.schelp create mode 100644 HelpSource/Tutorials/Event_patterns_and_LFOs.schelp create mode 100644 HelpSource/Tutorials/Event_patterns_and_array_args.schelp create mode 100644 HelpSource/Tutorials/HS_with_VarGui.schelp create mode 100644 HelpSource/Tutorials/Idev_suite.schelp create mode 100755 HelpSource/Tutorials/Live_Granulation.schelp create mode 100644 HelpSource/Tutorials/Other_event_and_pattern_shortcuts.schelp create mode 100644 HelpSource/Tutorials/PLx_and_live_coding_with_Strings.schelp create mode 100644 HelpSource/Tutorials/PLx_suite.schelp create mode 100644 HelpSource/Tutorials/PSx_stream_patterns.schelp create mode 100644 HelpSource/Tutorials/Sieves_and_Psieve_patterns.schelp create mode 100644 HelpSource/Tutorials/Smooth_Clipping_and_Folding.schelp create mode 100644 HelpSource/Tutorials/VarGui_shortcut_builds.schelp create mode 100644 HelpSource/Tutorials/attachments/Idev_suite/Idev_scheme_3.png create mode 100644 HelpSource/Tutorials/attachments/Smooth_Clipping_and_Folding/fold_examples.png create mode 100644 HelpSource/Tutorials/attachments/enum/graph.png create mode 100644 HelpSource/Tutorials/enum.schelp create mode 100755 HelpSource/Tutorials/kitchen_studies.schelp create mode 100644 LICENSE.txt create mode 100755 README.txt create mode 100644 Sounds/kitchen_sounds_1.wav create mode 100644 miSCellaneous_lib.quark diff --git a/.gitattributes.txt b/.gitattributes.txt new file mode 100644 index 0000000..22003a5 --- /dev/null +++ b/.gitattributes.txt @@ -0,0 +1 @@ +Help/* linguist-vendored \ No newline at end of file diff --git a/.gitignore.txt b/.gitignore.txt new file mode 100644 index 0000000..134ee11 --- /dev/null +++ b/.gitignore.txt @@ -0,0 +1,4 @@ + +# ignore gits in folders + +.git \ No newline at end of file diff --git a/Classes/DX/AbstractDX.sc b/Classes/DX/AbstractDX.sc new file mode 100644 index 0000000..b77fa93 --- /dev/null +++ b/Classes/DX/AbstractDX.sc @@ -0,0 +1,527 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +AbstractDX : UGen { + + *xr { |type = \mix, outRate = \ar, inOut, channelsArrayRef, fadeTime = 1, stepTime = 1, + fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, + fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, + initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, + allowFadeEnd = 1, size = nil, bus = nil, zeroThr = nil, doneAction = 0| + + var maxArgSize, args; + + args = [ + inOut, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, power, + curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, size, bus, zeroThr, doneAction + ]; + + #inOut, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, power, + curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, size, bus, zeroThr, doneAction = + this.unbubbleInputIfNecessary(*args); + + maxArgSize = (args.collect { |x| x.asArray.size }).maxItem; + + this.checkForWrongDrateInput(maxArgSize, inOut, fadeTime, stepTime, sine, + equalPower, power, curve); + + #inOut, fadeTime, stepTime, sine, equalPower, power, curve = + [inOut, fadeTime, stepTime, sine, equalPower, power, curve] + .collect { |x| x.miSC_Dmultiply(maxArgSize) }; + + + ^((type == \fanOut) || (type == \envFanOut)).if { + this.multiNewList([type, outRate, inOut, channelsArrayRef, fadeTime, stepTime, + fadeMode, sine, equalPower, power, curve, allowTypeSeq, fadeRate, maxFadeNum, + maxWidth, width, initOutOffset, maxDynOutOffset, dynOutOffset, allowFadeEnd, + size, bus, zeroThr, doneAction + ]); + 0.0 // no output + }{ + this.multiNewList([type, outRate, inOut, channelsArrayRef, fadeTime, stepTime, + fadeMode, sine, equalPower, power, curve, allowTypeSeq, fadeRate, maxFadeNum, + maxWidth, width, initOutOffset, maxDynOutOffset, dynOutOffset, allowFadeEnd, + size, bus, zeroThr, doneAction + ]) + } + } + + *new1 { |type, outRate, inOut, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, + sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, + fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, + maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, + size = nil, bus = nil, zeroThr, doneAction = 0| + + var index, trig, indexDrate, channelsArray, overlapChannelSize, thr = 1e-5, count, + maxCountNum, panPos, weight, durs, initForwardNum, compOldPanAz, channelStep, done, + doneDelayTime, weightAtInit, initMuteIndex, dc, dir, lincurve, source, env; + + this.checkForWrongWidthInput(maxWidth, width); + this.checkForWrongFadeTimeInput(fadeTime, stepTime, fadeMode); + + overlapChannelSize = maxWidth.ceil.asInteger + max(initOutOffset.ceil.asInteger, 0) + + maxDynOutOffset.ceil.asInteger + 1; + + channelsArray = channelsArrayRef.value; + channelsArray = this.replaceZeroesWithSilence(channelsArray.asUGenInput(this).asArray); + + // ensure right initForwardNum by tolerance + // for a given maxWidth the centre has to be at index 0 - see doc + + initForwardNum = ((maxWidth + 1 - thr) / 2).round.asInteger + + initOutOffset.ceil.asInteger + maxDynOutOffset.ceil.asInteger; + initMuteIndex = initOutOffset + (width + 1 / 2); + + (fadeMode == 0).if { + durs = Dstutter(2, fadeTime); + indexDrate = Dseries() - 1; + }{ + // double polling needed in these cases, thus Dstutter + switch(fadeMode, + 1, { + indexDrate = Dstutter(2, Dseries()) - 1; + durs = Dstutter(2, Dswitch1([stepTime, fadeTime], Dseq([0, 1], inf))); + }, + 2, { + indexDrate = Dseq([0, Dstutter(2, Dseries())]); + durs = Dstutter(2, Dswitch1([stepTime, fadeTime], Dseq([1, 0], inf))); + }, + 3, { + indexDrate = Dstutter(2, Dseries()) - 1; + fadeTime = Dstutter(2, fadeTime); + durs = Dstutter(2, Dswitch1([stepTime - fadeTime, fadeTime], Dseq([0, 1], inf))); + }, + 4, { + indexDrate = Dseq([0, Dstutter(2, Dseries())]); + fadeTime = Dstutter(2, fadeTime); + durs = Dstutter(2, Dswitch1([stepTime - fadeTime, fadeTime], Dseq([1, 0], inf))); + } + ); + }; + + indexDrate = indexDrate + initOutOffset; + trig = TDuty.perform(fadeRate, durs); + + count = case + { fadeMode == 0 } + { PulseCount.perform(fadeRate, trig) } + { [2, 4].includes(fadeMode) } + // count twice + { PulseCount.perform(fadeRate, ToggleFF.perform(fadeRate, trig)) } + { [1, 3].includes(fadeMode) } + // count twice and omit first trig + { PulseCount.perform(fadeRate, 1 - ToggleFF.perform(fadeRate, trig)) }; + + index = count % overlapChannelSize; + + maxCountNum = maxFadeNum; + [1, 3].includes(fadeMode).if { maxCountNum = maxCountNum + 1 }; + DetectSilence.perform(fadeRate, (1 - (count > maxCountNum)), doneAction: doneAction); + + allowFadeEnd = allowFadeEnd.asBoolean; + allowFadeEnd.if { + done = {} ! overlapChannelSize; + doneDelayTime = Timer.perform(fadeRate, trig) + }; + + // the array of bus indices + // new indices are polled from drate input 'inOut' + + inOut = { |i| + var initTrig, fadeTrig, demand; + + // first initForwardNum inOut indices must show up immediately for overlap + initTrig = ((i < initForwardNum).if { Impulse }{ DC }).perform(fadeRate, 0); + fadeTrig = (index + initForwardNum - 1 % overlapChannelSize - i).abs < thr; + + demand = Demand.perform( + fadeRate, + initTrig + fadeTrig, + 0, + inOut + ); + allowFadeEnd.if { done[i] = Done.kr(demand) }; + demand + } ! overlapChannelSize; + + // strange trigger logic needed here, allowFadeEnd = 0 saves a bit CPU + allowFadeEnd.if { + done = TDelay.kr( + DelayL.kr(done.sum, ControlDur.ir, ControlDur.ir), + A2K.kr(doneDelayTime) + ); + done = Trig1.kr(done > thr, inf) + }; + + // compensate PanAz ar bug with panPos and orientation in older SC versions + compOldPanAz = ((fadeRate == \kr) || (Main.versionAtLeast(3, 9))).not; + channelStep = compOldPanAz.if { 2 / width }{ 2 } / overlapChannelSize; + + // workhorse 1: angle stepping performed by DemandEnvGen + panPos = dynOutOffset + DemandEnvGen.perform(fadeRate, indexDrate, durs) * channelStep; + + // workhorse 2: channel distribution performed by PanAz + weight = PanAz.perform( + fadeRate, + overlapChannelSize, + DC.perform(fadeRate, 1), + allowFadeEnd.if { Gate.perform(fadeRate, panPos, 0.5 - done) }{ panPos }, + 1, + width, + // compensate PanAz ar bug with panPos and orientation in older SC versions + compOldPanAz.if { (1 - width) * 0.5 }{ 0 }; + ); + + // with extreme short durations occasional large values have been observed + // they are catched by Gate + weight = Gate.perform(fadeRate, weight, (weight >= 0) * (weight <= 1)); + + zeroThr.notNil.if { weight = weight * (weight > zeroThr) }; + + // lincurve helper Function + lincurve = { |x| x.lincurve_3_9(0, 1, 0, 1, curve * dir.sign) }; + + allowTypeSeq.asBoolean.not.if { + // static xfade type is most efficient + // determined by Integers for 'sine' and 'equalPower' + + // among static xfades most efficient for equalPower = sin = 1, + // that's what is done by PanAz, other cases treated here + + equalPower.asBoolean.not.if { + dir = HPZ1.perform(fadeRate, weight); + weight = sine.asBoolean.if { + lincurve.(weight.squared.pow(power)) + }{ + lincurve.((weight.asin * 2 / pi).pow(power)) + }; + }{ + sine.asBoolean.not.if { weight = (weight.asin * 2 / pi).sqrt } + } + }{ + // if xfade types should be sequenced + // all must run in parallel - this has to be allowed explicitely + (fadeMode > 0).if { + sine = Dstutter(2, sine); + equalPower = Dstutter(2, equalPower); + power = Dstutter(2, power); + curve = Dstutter(2, curve); + }; + sine = Demand.perform(fadeRate, trig, 0, sine); + equalPower = Demand.perform(fadeRate, trig, 0, equalPower); + power = Demand.perform(fadeRate, trig, 0, power); + curve = Demand.perform(fadeRate, trig, 0, curve); + dir = HPZ1.perform(fadeRate, weight); + + weight = Select.perform(fadeRate, sine * 2 + equalPower, [ + lincurve.((weight.asin * 2 / pi).pow(power)), + (weight.asin * 2 / pi).sqrt, + lincurve.(weight.squared.pow(power)), + weight + ]) + }; + + // difference between DX classes + ^case + { (type == \mix) || (type == \mixIn) }{ + Mix({ |i| + var in = (type == \mix).if { + Select.perform(outRate, inOut[i], channelsArray) + }{ + In.perform(outRate, inOut[i]) + }; + var muteAtInit = initForwardNum + count >= i; + weight[i] * in * muteAtInit; + } ! overlapChannelSize) + } + { (type == \fanOut) || (type == \envFanOut) }{ + source = (type == \fanOut).if { channelsArray }{ 1 }; + { |i| + var muteAtInit = initForwardNum + count >= i; + Out.perform(outRate, inOut[i], weight[i] * source * muteAtInit); + } ! overlapChannelSize; + } + { (type == \fan) || (type == \envFan) }{ + bus.isNil.if { + // for larger sizes we have a ugen number growth of quadratic order, + // thus rather pass a bus then + dc = { |i| DC.perform(fadeRate, i) ! overlapChannelSize } ! size; + weightAtInit = { |i| initMuteIndex + count >= i } ! overlapChannelSize; + weight = weight * weightAtInit; + + env = { |i| Mix(((dc[i] - (inOut.round)).abs < thr) * weight) } ! size; + + (type == \envFan).if { + env + }{ + // for multichannel source we need to "convolve" output + channelsArray = channelsArray.asArray; + size.collect { |i| + var sum = 0; + ([i + 1, channelsArray.size, size - i + channelsArray.size - 1].minItem).do { |j| + sum = sum + (env[i-j] * channelsArray[j]) + }; + sum + } + } + }{ + source = (type == \fan).if { channelsArray }{ 1 }; + { |i| + var weightAtInit = initMuteIndex + count >= i; + Out.perform( + outRate, bus + inOut[i] + thr, + weight[i] * weightAtInit * source + ) + } ! overlapChannelSize; + In.perform(outRate, bus, size); + } + } + } + + // restrict to possible drate arguments + *checkForWrongDrateInput { |maxArgSize, inOut, fadeTime, stepTime, sine, equalPower, power, curve| + + if ((maxArgSize > 1) and: { + [inOut, fadeTime, stepTime, sine, equalPower, power, curve].any { |x| + x.isKindOf(DUGen) or: { + x.isKindOf(SequenceableCollection) and: { + // do deep check, but only for DUGens + (x.size < maxArgSize) and: { x.flat.any { |y| y.isKindOf(DUGen) } } + } + } + } + }) { + SimpleInitError("For multichannel expansion demand rate " ++ + "ugens, that are needed more than once, have to be " ++ + "wrapped into Functions, see help file" + ).throw + }; + } + + *checkForWrongWidthInput { |maxWidth, width| + maxWidth.isNumber.not.if { + SimpleInitError("maxWidth must be a number").throw + }; + ((maxWidth.isNumber && width.isNumber) and: { width > maxWidth }).if { + SimpleInitError("width must not be larger than maxWidth").throw + }; + (Main.versionAtLeast(3, 9)).not and: { + width.isNumber.not.if { + SimpleInitError("In SC versions before 3.9 width is not modulatable, " ++ + "it must be a number" + ).throw + } + }; + } + + *checkForWrongFadeTimeInput { |fadeTime, stepTime, fadeMode| + ((fadeTime.isNumber && stepTime.isNumber && ([3, 4].includes(fadeMode))) and: { + fadeTime >= stepTime }).if { + SimpleInitError("fadeTime must not be larger than stepTime").throw + } + } + + *unbubbleInputIfNecessary { |... argList| + ^argList.collect { |item| + ((item.isKindOf(SequenceableCollection)) and: { item.size == 1 }).if { + item[0] + }{ + item + }; + } + } + +} + + +DXMix : AbstractDX { + + *ar { |in, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0| + + ^this.xr(\mix, \ar, in, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } + + *kr { |in, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \kr, maxFadeNum = inf, maxWidth = 2, + width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, + zeroThr = nil, doneAction = 0| + + ^this.xr(\mix, \kr, in, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } +} + +DXMixIn : AbstractDX { + + *ar { |in, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0| + + ^this.xr(\mixIn, \ar, in, `[], fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } + + *kr { |in, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \kr, maxFadeNum = inf, maxWidth = 2, + width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, + zeroThr = nil, doneAction = 0| + + ^this.xr(\mixIn, \kr, in, `[], fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } +} + + +DXFan : AbstractDX { + + *ar { |out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0| + + ^this.xr(\fan, \ar, out, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, size, bus, zeroThr, doneAction + ); + } + + *kr { |out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \kr, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0| + + ^this.xr(\fan, \kr, out, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, size, bus, zeroThr, doneAction + ); + } +} + + +DXEnvFan : AbstractDX { + + *ar { |out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0| + + ^this.xr(\envFan, \ar, out, `[], fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, maxDynOutOffset, + dynOutOffset, allowFadeEnd, size, bus, zeroThr, doneAction + ); + } + + *kr { |out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \kr, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0| + + ^this.xr(\envFan, \kr, out, `[], fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, size, bus, zeroThr, doneAction + ); + } +} + + +DXFanOut : AbstractDX { + + *ar { |out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0| + + ^this.xr(\fanOut, \ar, out, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } + + *kr { |out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \kr, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0| + + ^this.xr(\fanOut, \kr, out, channelsArrayRef, fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } +} + + +DXEnvFanOut : AbstractDX { + + *ar { |out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0| + + ^this.xr(\envFanOut, \ar, out, `[], fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } + + *kr { |out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, + power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \kr, + maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, + dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0| + + ^this.xr(\envFanOut, \kr, out, `[], fadeTime, stepTime, fadeMode, sine, equalPower, + power, curve, allowTypeSeq, fadeRate, maxFadeNum, maxWidth, width, initOutOffset, + maxDynOutOffset, dynOutOffset, allowFadeEnd, nil, nil, zeroThr, doneAction + ); + } +} + + + ++Object { + miSC_Dmultiply { ^this } +} + ++Function { + miSC_Dmultiply { |n| ^{ this } ! n } +} + ++SequenceableCollection { + miSC_Dmultiply { |n| ^{ |i| this.wrapAt(i) } ! n } +} + diff --git a/Classes/DX/extUGen.sc b/Classes/DX/extUGen.sc new file mode 100644 index 0000000..a0f5c10 --- /dev/null +++ b/Classes/DX/extUGen.sc @@ -0,0 +1,94 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// this provides the newer version of lincurve for older SC versions with DX UGens +// Credits to Tim Blechmann and Julian Rohrhuber + + ++ UGen { + lincurve_3_9 { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; + var grow, a, b, scaled, curvedResult; + if (curve.isNumber and: { abs(curve) < 0.125 }) { + ^this.linlin(inMin, inMax, outMin, outMax, clip) + }; + grow = exp(curve); + a = outMax - outMin / (1.0 - grow); + b = outMin + a; + scaled = (this.prune(inMin, inMax, clip) - inMin) / (inMax - inMin); + + curvedResult = b - (a * pow(grow, scaled)); + + if (curve.rate == \scalar) { + ^curvedResult + } { + ^Select.perform(this.methodSelectorForRate, abs(curve) >= 0.125, [ + this.linlin(inMin, inMax, outMin, outMax, clip), + curvedResult + ]) + } + } +} + ++ AbstractFunction { + lincurve_3_9 { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; + ^this.composeNAryOp('lincurve_3_9', [inMin, inMax, outMin, outMax, curve, clip]) + } +} + ++ SequenceableCollection { + lincurve_3_9 { arg ... args; ^this.multiChannelPerform('lincurve_3_9', *args) } +} + ++ SimpleNumber { + lincurve_3_9 { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; + var grow, a, b, scaled; + switch(clip, + \minmax, { + if (this <= inMin, { ^outMin }); + if (this >= inMax, { ^outMax }); + }, + \min, { + if (this <= inMin, { ^outMin }); + }, + \max, { + if (this >= inMax, { ^outMax }); + } + ); + if (abs(curve) < 0.001) { + // If the value should be clipped, it has already been clipped (above). + // If we got this far, then linlin does not need to do any clipping. + // Inlining the formula here makes it even faster. + ^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin; + }; + + grow = exp(curve); + a = outMax - outMin / (1.0 - grow); + b = outMin + a; + scaled = (this - inMin) / (inMax - inMin); + + ^b - (a * pow(grow, scaled)); + } +} + diff --git a/Classes/Enumeration/extInteger.sc b/Classes/Enumeration/extInteger.sc new file mode 100644 index 0000000..501a20b --- /dev/null +++ b/Classes/Enumeration/extInteger.sc @@ -0,0 +1,67 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Integer { + enum { |pool, function = true, evalAtZero = false, type = 0, order = true, maxNum = inf| + // type 0: one array for all levels + // type 1: array of pools (size must equal receiver) + + var allCols, currentCol, currentIndex = 0, indexCol, + endOfEnum = false, currentPool, check, item, count = 0; + + order.not.if { + pool = (type == 0).if { pool.scramble }{ pool.collect(_.scramble) }; + }; + indexCol = -1!this; + currentCol = 0!this; + while { endOfEnum.not }{ + indexCol[currentIndex] = indexCol[currentIndex] + 1; + currentPool = (type == 0).if { pool }{ pool[currentIndex] }; + (indexCol[currentIndex] >= (currentPool.size)).if { + indexCol[currentIndex] = -1; + currentIndex = currentIndex - 1; + }{ + item = currentPool.at(indexCol[currentIndex]); + + ((currentIndex == 0) && evalAtZero.not).if { + true + }{ + function.(item, currentIndex, currentCol, indexCol) + }.if { + currentCol[currentIndex] = item; + (currentIndex == (this - 1)).if { + allCols = allCols.add(currentCol.deepCopy); + count = count + 1; + (count == maxNum).if { endOfEnum = true }; + }{ + currentIndex = currentIndex + 1 + } + } + }; + (currentIndex == -1).if { endOfEnum = true }; + }; + ^allCols; + } +} diff --git a/Classes/FFT/PV_UGens.sc b/Classes/FFT/PV_UGens.sc new file mode 100644 index 0000000..3e286e8 --- /dev/null +++ b/Classes/FFT/PV_UGens.sc @@ -0,0 +1,73 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PV_BinRange : PV_ChainUGen { + + *new { |buffer, loBin, hiBin| + ^this.multiNew(\control, buffer, loBin, hiBin) + } + + *new1 { |rate, buffer, loBin, hiBin| + var bufSizes = buffer.miSC_getFFTbufSizes, wipe; + var bufSize = bufSizes[0]; + var chain_clipped = bufSizes.collect { LocalBuf(bufSize) }; + + chain_clipped = PV_Copy(buffer, chain_clipped); + + wipe = loBin * 2 / bufSize; + chain_clipped = PV_BrickWall(chain_clipped, wipe); + + wipe = hiBin * 2 / bufSize - 1; + chain_clipped = PV_BrickWall(chain_clipped, wipe); + + ^chain_clipped[0] + } +} + +PV_BinGap : PV_ChainUGen { + + *new { |buffer, loBin, hiBin| + ^this.multiNew(\control, buffer, loBin, hiBin) + } + + *new1 { |rate, buffer, loBin, hiBin| + var bufSizes = buffer.miSC_getFFTbufSizes, wipe; + var bufSize = bufSizes[0]; + var chain_gap_1 = bufSizes.collect { LocalBuf(bufSize) }; + var chain_gap_2 = bufSizes.collect { LocalBuf(bufSize) }; + + chain_gap_1 = PV_Copy(buffer, chain_gap_1); + chain_gap_2 = PV_Copy(buffer, chain_gap_2); + + wipe = loBin - 1 * 2 / bufSize - 1; + chain_gap_1 = PV_BrickWall(chain_gap_1, wipe); + + wipe = hiBin + 1 * 2 / bufSize; + chain_gap_2 = PV_BrickWall(chain_gap_2, wipe); + + ^PV_Add(chain_gap_1, chain_gap_2)[0]; + } +} + diff --git a/Classes/FFT/extFFT.sc b/Classes/FFT/extFFT.sc new file mode 100644 index 0000000..edeceac --- /dev/null +++ b/Classes/FFT/extFFT.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++ FFT { + miSC_getFFTbufSizes { + ^[this.inputs[0].inputs[1]] + } +} diff --git a/Classes/FFT/extSequenceableCollection.sc b/Classes/FFT/extSequenceableCollection.sc new file mode 100644 index 0000000..0292723 --- /dev/null +++ b/Classes/FFT/extSequenceableCollection.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++ SequenceableCollection { + miSC_getFFTbufSizes { + ^this.collect { |x| x.miSC_getFFTbufSizes[0] } + } +} diff --git a/Classes/HS/HelpSynth.sc b/Classes/HS/HelpSynth.sc new file mode 100755 index 0000000..ebd2177 --- /dev/null +++ b/Classes/HS/HelpSynth.sc @@ -0,0 +1,338 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +HS : HelpSynth {} + +HelpSynth { + classvar <>all; + var <>ugenFuncs, <>helpSynthDefs, <>playingHelpSynths, + <>size, <>bus, <>server, <>helpSynthString, <>controlNames, + <>trigSynths, <>trigSynthDef, <>trigString, <>initstring, <>inputErrString, <>postOSC, + <>trigMsgIDCounter = -1, <>demandIndexOffset = 0, <>lastDemandIndexOffset = 0, <>inputCheck, + <>isListening = false, <>isPlaying = false, <>isRunning = false, <>isPHelpSynthPlaying = false, + <>hasJustStartedWithPause = false, + + <>granularity = 200, // time grains per second, quantization for bookkeeping (demand message comprehension) + // not used for scheduling events + <>initSeconds, // time grains reset at PHS player start + + <>helpSynthAhead = 0.0001, + <>cleanupDelay = 0.01, + <>sequentialSchedShift = 0.0001, // scheduling events at same logical time + <>demandLatency, // = help synth latency + <>respondLatency, // time given to the response to be safely received by the client on time (at total latency) + <>totalLatency, // demandLatency + respondLatency = + // total (client side) logical difference between demand event and receive event + + <>mainPHSplayer, <>otherPHSusePlayers, + <>demandStreams_indexOffsets, <>receiveStreams_indexOffsets, + + // OSC bookkeeping when PHSparPlayer or PHSusePlayer involved: + + <>trigMsgIDs_times, // IdentityDictionary: trigMsgID -> time (in grains) + <>times_demandNums, // IdentityDictionary: time (in grains) -> demand num / array of (hs indexed) demand nums + <>times_vals, // IdentityDictionary: time (in grains) -> synth value / synth value array + + // Lists with one item for each demand index, they may grow with PHSusePlayers involved + <>times_durs, // List of IdentityDictionaries: time (in grains) -> duration (in beats) + <>timeQueues; // List of PriorityQueues + *basicNew { |server, ugenFunc, demandLatency = 0.15, respondLatency = 0.15, postOSC = false, granularity = 200, inputCheck = true| + ^super.new.ugenFuncs_(ugenFunc).server_(server).demandLatency_(demandLatency) + .respondLatency_(respondLatency).postOSC_(postOSC).granularity_(granularity).inputCheck_(inputCheck); + } + + *new { |server, ugenFunc, demandLatency = 0.15, respondLatency = 0.15, postOSC = false, granularity = 200, inputCheck = true| + ^this.basicNew(server, ugenFunc, demandLatency, respondLatency, postOSC, granularity, inputCheck).commonInit.addInit; + } + + *add { |helpSynth| + var old; + old = all.findMatch(helpSynth); + old.notNil.if { all.remove(old) }; + all.add(helpSynth); + } + + *remove { |helpSynth| all.remove(helpSynth) } + + *clear { all = Set[] } + + add { this.class.add(this) } + + remove { all.remove(this) } + + inputError {|str| + Error("\n Wrong HS input - " ++ str ++ "\n").throw + } + + commonInputCheck { + (server.isMemberOf(Server) and: { server.serverRunning }).not.if { + this.inputError("server must be a running Server") + }; + (demandLatency.isKindOf(Number) and: { demandLatency > 0 } ).not.if { + this.inputError("demandLatency must be a Number > 0") + }; + (respondLatency.isKindOf(Number) and: { respondLatency > 0 } ).not.if { + this.inputError("respondLatency must be a Number > 0") + }; + (postOSC.isNil or: { postOSC.isKindOf(Boolean) } ).not.if { + this.inputError("postOSC must be a Boolean") + }; + (granularity.isKindOf(Integer) and: { granularity > 0 } ).not.if { + this.inputError("granularity must be an Integer > 0") + }; + } + + addInputCheck { + ugenFuncs.isMemberOf(Function).not.if { + this.inputError("ugenFunc must be a (ugenGraph)Function") + }; + } + + commonInit { + inputCheck.if { this.commonInputCheck }; + totalLatency = demandLatency + respondLatency; + trigMsgIDs_times = IdentityDictionary.new; + + times_vals = IdentityDictionary.new; + times_demandNums = IdentityDictionary.new; + demandStreams_indexOffsets = IdentityDictionary.new; + receiveStreams_indexOffsets = IdentityDictionary.new; + times_durs = List.new; + timeQueues = List.new; + + this.class.all.isNil.if { this.class.all = Set[] }; + this.add; + + otherPHSusePlayers = List.new; + initstring = Main.elapsedTime.asString; + helpSynthString = "hs" ++ initstring; + trigString = "trig" ++ initstring; + trigSynthDef = this.makeTrigSynthDef; + trigSynths = List.new; + this.resetInitSeconds; + } + + addInit { + size = 1; + inputCheck.if { this.addInputCheck }; + helpSynthDefs = [(ugenFuncs.asSynthDef.name = helpSynthString).perform(Main.versionAtMost(3,3).if { \memStore }{ \add })]; + helpSynthDefs.miSC_areControlRateSynthDefs.not.if { Error("help synths should be control rate \n").throw }; + controlNames = ugenFuncs.def.argNames; + playingHelpSynths = Array.newClear(1); + } + + resetInitSeconds { initSeconds = Main.elapsedTime; } + + allocBus { + // PHSplayer controls allocation and deallocation + bus.isNil.if { + bus = Bus.control(server, size); + }{ + "Bus already allocated".warn; + } + } + + makeTrigSynthDef { + ^SynthDef(trigString ++ "control", { |t_tr = 0, trigMsgID, inBus| + SendTrig.kr(t_tr, trigMsgID, In.kr(inBus,1)) + }, [\tr]).send(server); + } + + listen { |num = 1, latency| + // installs additional num trigger synths for sending osc messages + // every demand index gets its own trigger synth + var ensureListenFactor = 0.8; + this.isListening.not.if { isListening = true; }; + num.do({ |i| + var trigSynth = Synth.basicNew(trigString ++ \control.asString, server); + server.sendBundle(latency ?? demandLatency * ensureListenFactor, + trigSynth.newMsg(args: [\inBus, bus] )) ; + trigSynths.add(trigSynth); + + times_durs.add(IdentityDictionary.new); + timeQueues.add(PriorityQueue.new); + // CmdPeriod.remove(trigSynth); + }); + } + + // makeResponder { |trigSynthID, trigMsgID| + // ^OSCpathResponder(server.addr, ['/tr', trigSynthID, trigMsgID], { |time, responder, message| + // var timeGrains, demandIndices, val = message[3]; + // + // timeGrains = trigMsgIDs_times.removeAt(trigMsgID); + // postOSC.if { + // "time in grains: ".post; timeGrains.post; + // " val: ".post; val.postln; + // }; + // times_vals.put(timeGrains, val); + // responder.remove; + // }); + // } + + makeResponder { |trigSynthID, trigMsgID| + ^OSCFunc( + { |message| + var timeGrains, demandIndices, val = message[3]; + + timeGrains = trigMsgIDs_times.removeAt(trigMsgID); + postOSC.if { + "time in grains: ".post; timeGrains.post; + " val: ".post; val.postln; + }; + times_vals.put(timeGrains, val); + }, + '/tr', + server.addr, + argTemplate: [trigSynthID, trigMsgID] + ).oneShot; + } + + updateDemandIndexOffsets { |pHelpSynthUse| + lastDemandIndexOffset = demandIndexOffset; + demandIndexOffset = demandIndexOffset + pHelpSynthUse.relDemandIndexUserNums.size; + } + + play { |args, latency| + var synth = Synth.basicNew(helpSynthString, server); + playingHelpSynths.put(0, synth); + server.sendBundle(latency ?? demandLatency, synth.newMsg(server, + [\i_out, bus.index, \out, bus] ++ (args ?? []) )); + // CmdPeriod.remove(synth); + isPlaying = true; + isRunning = true; + } + + schedRun { |flag, latency| +// this.isPlaying.not.if { Error("HS not being played \n").throw }; +// server.sendBundle(latency ?? demandLatency, playingHelpSynths.at(0).runMsg(flag)); +// isRunning = flag; + + this.isPlaying.if { + server.sendBundle(latency ?? demandLatency, playingHelpSynths.at(0).runMsg(flag)); + isRunning = flag; + }; + + } + + sleep { |latency| + this.isListening.if { + trigSynths.do({|x| server.sendBundle(latency ?? demandLatency, x.freeMsg); }); + trigSynths = List.new; + isListening = false; + } + } + + stop { |latency| + this.isPlaying.if { + playingHelpSynths.do({ |x| x.notNil.if { server.sendBundle(latency ?? demandLatency, x.freeMsg) } }); isPlaying = false; + isRunning = false; + }; + SystemClock.sched((latency ?? demandLatency) + cleanupDelay, { this.clearBookkeeping; }); + } + + clearBookkeeping { + trigMsgIDs_times.clear; + times_vals.clear; + times_durs.clear; + timeQueues.clear; + times_demandNums.clear; + demandStreams_indexOffsets.clear; + receiveStreams_indexOffsets.clear; + + otherPHSusePlayers.clear; + mainPHSplayer = nil; + playingHelpSynths.clear; + demandIndexOffset = 0; + lastDemandIndexOffset = 0; + trigMsgIDCounter = -1; + } + + free { |latency| + var late = latency ?? demandLatency; + this.isPHelpSynthPlaying.if { + mainPHSplayer.free; // calls free again + }{ + this.stop(late).sleep(late).busFree(late); + } + } + + busFree { |latency| + SystemClock.sched((latency ?? demandLatency) + cleanupDelay, { bus.notNil.if { bus.free; bus = nil; } }) + } + + makeAdaptedQuants { |clock, quant, adaptQuant = true, quantBufferTime = 0.2, startQuantDelay = 0| + // quantBufferTime, startQuantDelay in seconds + // startQuantDelay used for resume in case of help synth switch + var startQuant, demandQuant, receiveQuant, qu, ph, off, + beatsToNextTimeOnGrid, periodShiftFactor, secureNextTime, + nextTimeOnGridCheckSum, nextTimeOnGridIsPossible; + + (quant.isKindOf(Quant) || quant.isNil).not.if { + Error("quant must be instance of Quant or nil").throw; + }; + + qu = quant.isNil.if { 0 } { quant.quant ?? 0 }; + ph = quant.isNil.if { 0 } { quant.phase ?? 0 }; + off = quant.isNil.if { 0 } { quant.timingOffset ?? 0 }; + + adaptQuant.if { + [qu,ph,off].do({|x| + ((x.isNumber) && (x >= 0)).not.if { Error("quant, phase and offset must be numbers >= 0").throw; } + }); + + beatsToNextTimeOnGrid = (clock.nextTimeOnGrid(qu,ph) - clock.beats); + // nextTimeToGrid must allow total latency to take place before + nextTimeOnGridCheckSum = beatsToNextTimeOnGrid - ((totalLatency + quantBufferTime + helpSynthAhead) * clock.tempo); + nextTimeOnGridIsPossible = (nextTimeOnGridCheckSum > 0); + + // secureNextTime in beats ! + (qu == 0).if { + // qu = 0 and ph = 0: "as soon as possible" + // ph > 0 is overruled, if it doesn't allow required latency + secureNextTime = max( (totalLatency + quantBufferTime + helpSynthAhead) * clock.tempo, ph); + }{ + nextTimeOnGridIsPossible.if { + secureNextTime = helpSynthAhead * clock.tempo + beatsToNextTimeOnGrid; + }{ + // step to the nearest period with enough headroom + periodShiftFactor = (nextTimeOnGridCheckSum.neg / qu).ceil; + secureNextTime = periodShiftFactor * qu + beatsToNextTimeOnGrid + (helpSynthAhead * clock.tempo); + } + } + }; + startQuant = Quant(qu, clock.miSC_getPhaseFromTimeToNextBeat(qu, secureNextTime - ((helpSynthAhead + totalLatency - startQuantDelay) * clock.tempo)), off); + demandQuant = Quant(qu, clock.miSC_getPhaseFromTimeToNextBeat(qu, secureNextTime - (totalLatency * clock.tempo)), off); + receiveQuant = Quant(qu, clock.miSC_getPhaseFromTimeToNextBeat(qu, secureNextTime), off); + ^[startQuant, demandQuant, receiveQuant]; + } + + currentAdaptedQuant { |clock, quant, adaptQuant = true, quantBufferTime = 0.2| + ^this.makeAdaptedQuants(clock, quant, adaptQuant, quantBufferTime).at(2); + } + + nextTrigMsgID { ^trigMsgIDCounter = trigMsgIDCounter + 1 } + isPHSplaying { ^this.isPHelpSynthPlaying } + isPHSplaying_ {|x| this.isPHelpSynthPlaying_(x) } +} + diff --git a/Classes/HS/HelpSynthPar.sc b/Classes/HS/HelpSynthPar.sc new file mode 100755 index 0000000..5a78a7c --- /dev/null +++ b/Classes/HS/HelpSynthPar.sc @@ -0,0 +1,217 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +HSpar : HelpSynthPar {} + +HelpSynthPar : HelpSynth { + var <>currentSwitchIndex, <>currentHSindices, <>lastIndex, <>lastPause, <>switchCounter = -1, + + // OSC bookkeeping when PHSparPlayer or PHSusePlayer involved: + + // size fixed at init time: + + <>hsRunnings, // array of booleans: HelpSynth running status + + // variable size: + + <>times_switchIndices, // IdentityDictionary: time (in grains) -> switch index + <>trigMsgIDs_hsIndices, // IdentityDictionary: trigMsgID -> HelpSynth index + <>times_hsIndices, // IdentityDictionary: time (in grains) -> HelpSynth index array + // indicates all HelpSynth indices triggered at a time + + // Lists with one item for each demand index, they may grow with PHSusePlayers involved + <>times_theseHSindices; // List of IdentityDictionaries: time (in grains) -> HelpSynth index array + // for each demand index and time it indicates all triggered HelpSynth indices + + + *basicNew { |server, ugenFuncs, demandLatency = 0.15, respondLatency = 0.15, postOSC = false, granularity = 200, inputCheck = true| + ^super.basicNew(server, ugenFuncs, demandLatency, respondLatency, postOSC, granularity).inputCheck_(inputCheck); + } + + *new { |server, ugenFuncs, demandLatency = 0.15, respondLatency = 0.15, postOSC = false, granularity = 200, inputCheck = true| + ^this.basicNew(server, ugenFuncs, demandLatency, respondLatency, postOSC, granularity, inputCheck).commonInit.addInit; + } + + inputError {|str| + Error("\n Wrong HSpar input - " ++ str ++ "\n").throw + } + + addInputCheck { + (ugenFuncs.isKindOf(SequenceableCollection) and: + { ugenFuncs.every(_.isMemberOf(Function)) } ).not.if { + this.inputError("ugenFuncs must be a SequenceableCollection of (ugenGraph)Functions") + }; + } + + addInit { + inputCheck.if { this.addInputCheck }; + size = ugenFuncs.size; + times_switchIndices = IdentityDictionary.new; + trigMsgIDs_hsIndices = IdentityDictionary.new; + times_hsIndices = IdentityDictionary.new; + playingHelpSynths = Array.newClear(size); + times_theseHSindices = List.new; + hsRunnings = Array.fill(size, false); + + helpSynthDefs = ugenFuncs.collect {|item,i| (item.asSynthDef.name = helpSynthString ++ + "_" ++ i.asString).perform(Main.versionAtMost(3,3).if { \memStore }{ \add }) + }; + helpSynthDefs.miSC_areControlRateSynthDefs.not.if { Error("help synths should be control rate \n").throw }; + controlNames = ugenFuncs.collect({|x| x.def.argNames}); + } + + sendNewMsg { |synth, args, bus| + server.sendBundle(demandLatency, synth.newMsg(server, [\i_out, bus, \out, bus] ++ args)); + } + + listen { |num = 1, latency| + // num: number of demand indices + // installs additional trigger synths for sending osc messages + // every demand index gets trigger synths for each help synth + var ensureListenFactor = 0.8, trigSynth, counter = 0; + this.isListening.not.if { isListening = true; }; + num.do({|i| + helpSynthDefs.do({|x,j| + trigSynth = Synth.basicNew(trigString ++ \control.asString, server); + server.sendBundle(demandLatency, + trigSynth.newMsg(args: [\inBus, bus.index + counter] )) ; + counter = counter + 1; + trigSynths.add(trigSynth); + // CmdPeriod.remove(trigSynth); + }); + times_durs.add(IdentityDictionary.new); + timeQueues.add(PriorityQueue.new); + times_theseHSindices.add(IdentityDictionary.new); + }); + } + +/* makeResponder { |trigSynthID, trigMsgID| + ^OSCpathResponder(server.addr, ['/tr', trigSynthID, trigMsgID], { |time, responder, message| var timeGrains, hsIndex, hsIndices, val = message[3], vals; + + timeGrains = trigMsgIDs_times.removeAt(trigMsgID); + hsIndex = trigMsgIDs_hsIndices.removeAt(trigMsgID); + postOSC.if { + "time in grains: ".post; timeGrains.post; + " hsIndex: ".post; hsIndex.post; + " val: ".post; val.postln; + }; + hsIndices = times_hsIndices.removeAt(timeGrains); + vals = times_vals.removeAt(timeGrains); + vals = (vals ?? Array.newClear(size)); + vals[hsIndex] = val; + times_vals.put(timeGrains, vals); + responder.remove; + } + ) + }*/ + + makeResponder { |trigSynthID, trigMsgID| + ^OSCFunc( + { |message| + var timeGrains, hsIndex, hsIndices, val = message[3], vals; + + timeGrains = trigMsgIDs_times.removeAt(trigMsgID); + hsIndex = trigMsgIDs_hsIndices.removeAt(trigMsgID); + postOSC.if { + "time in grains: ".post; timeGrains.post; + " hsIndex: ".post; hsIndex.post; + " val: ".post; val.postln; + }; + hsIndices = times_hsIndices.removeAt(timeGrains); + vals = times_vals.removeAt(timeGrains); + vals = (vals ?? Array.newClear(size)); + vals[hsIndex] = val; + times_vals.put(timeGrains, vals); + }, + '/tr', + server.addr, + argTemplate: [trigSynthID, trigMsgID] + ).oneShot + } + + play { |index, args, switchOn, switchOff, set, hsStartIndices, latency| + var synth, late = latency ?? demandLatency; + + this.isListening.not.if { Error("HelpSynthPar not listening \n").throw }; + switchCounter = switchCounter + 1; + (switchCounter == 0).if { + // .start could have been called before + this.isPlaying.not.if { + size.do({|i| + synth = Synth.newPaused(helpSynthString ++ "_" ++ i.asString, + [\i_out, bus.index + i, \out, bus.index + i] ++ ((index == i).if { args } { [] }), + server); + playingHelpSynths.put(i,synth); + // CmdPeriod.remove(synth); + }) + }; + (switchOn.if { hsStartIndices ++ [index] } { hsStartIndices }).asSet.do({|i| + server.sendBundle(late, playingHelpSynths[i].runMsg(true)); + hsRunnings[i] = true; + }); + }{ + // pause last synth only if index changes + (lastPause && (lastIndex != index)).if { + server.sendBundle(late, playingHelpSynths[lastIndex].runMsg(false)); + hsRunnings[index] = false; + }; + set.if { + switchOn.if { + server.sendBundle(late, (playingHelpSynths[index]).setMsg(*args), playingHelpSynths[index].runMsg(true)); + hsRunnings[index] = true; + }{ + server.sendBundle(late, (playingHelpSynths[index]).setMsg(*args)); + } + }; + }; + lastIndex = index; + lastPause = switchOff; + isPlaying = true; + } + + schedRun { |flag, latency, hsIndices| + // this.isPlaying.not.if { Error("PHSpar not being played \n").throw }; + + this.isPlaying.if { + server.sendBundle(latency ?? demandLatency, + *hsIndices.collect({|x| hsRunnings[x] = flag; playingHelpSynths[x].runMsg(flag)}) + ); + }; + } + + clearBookkeeping { + this.superPerform(\clearBookkeeping); + times_switchIndices.clear; + trigMsgIDs_hsIndices.clear; + times_theseHSindices.clear; + times_hsIndices.clear; + hsRunnings.fill(false); + + switchCounter = -1; + lastIndex = nil; + lastPause = nil; + currentSwitchIndex = nil; + } +} diff --git a/Classes/HS/PHelpSynth.sc b/Classes/HS/PHelpSynth.sc new file mode 100644 index 0000000..f604a42 --- /dev/null +++ b/Classes/HS/PHelpSynth.sc @@ -0,0 +1,77 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +PHS : PHelpSynth {} + +PHelpSynth : PHelpSynthUse { + var <>helpSynthArgs; + + *basicNew { |helpSynth, helpSynthArgs ... pbindArgs| + ^super.basicNew(helpSynth, *pbindArgs).helpSynthArgs_(helpSynthArgs); + } + + *new { |helpSynth, helpSynthArgs ... pbindArgs| + ^this.basicNew(helpSynth, helpSynthArgs, *pbindArgs).commonInit; + } + + inputError { |str| + Error("\nWrong PHS input - " ++ str ++ "\n").throw + } + + addInputCheck { + helpSynth.isKindOf(HelpSynthPar).if { + this.inputError("helpSynth must be an instance of HS") + }; + (helpSynthArgs.isNil || (helpSynthArgs.isKindOf(SequenceableCollection) and: { + helpSynthArgs.miSC_isPossibleHelpSynthArgs(helpSynth.controlNames) })).not.if { + this.inputError("helpSynthArgs must be collection of key / value pairs, \n" ++ + "keys: control names of defined help synth \n" ++ + "values: control values or functions which produce them \n") + }; + } + + play { |clock, quant, hsPlay| + // dummy arg hsPlay + var warnMsg = "HS already playing - use " ++ + "PHSuse for using a playing or pausing HS (or stop and free by Cmd-.)\n"; + (helpSynth.isPlaying && helpSynth.hasJustStartedWithPause.not).if { + warnMsg.warn + }{ + helpSynth.isPHSplaying = true; + ^PHelpSynthPlayer(this).play(clock, quant.asQuant, true); + } + } + + // for use with VarGui + asTask { |clock, quant, hsStop = false, hsPlay = true, newEnvir = true, removeCtrWithCmdPeriod = true| + var envir, task, player = this, controller; + envir = newEnvir.if { () }{ currentEnvironment }; + task = envir.use { Task { 1e5.wait } }; + controller = SimpleController(task) + .put(\userPlayed, { envir.use { player = player.play(clock: clock, quant: quant.asQuant, hsPlay: hsPlay) } }) + .put(\userStopped, { player.stop(hsStop) }); + removeCtrWithCmdPeriod.if { CmdPeriod.doOnce { controller.remove } }; ^task + } + +} diff --git a/Classes/HS/PHelpSynthPar.sc b/Classes/HS/PHelpSynthPar.sc new file mode 100644 index 0000000..7727b74 --- /dev/null +++ b/Classes/HS/PHelpSynthPar.sc @@ -0,0 +1,132 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PHSpar : PHelpSynthPar {} + +PHelpSynthPar : PHelpSynthParUse { + var <>startPattern, <>switchDur, <>switchIndex, <>helpSynthArgs, <>switchOn, <>switchOff, <>set, <>hsStartIndices; + + *basicNew { |helpSynthPar, switchDur = 10000, switchIndex = 0, helpSynthArgs, pbindArgs, hsIndices, switchOn = false, switchOff = false, set = true, hsStartIndices = \all| + ^super.basicNew(helpSynthPar, pbindArgs, hsIndices).switchDur_(switchDur).switchIndex_(switchIndex).helpSynthArgs_(helpSynthArgs) + .switchOn_(switchOn).switchOff_(switchOff).set_(set).hsStartIndices_(hsStartIndices); + } + + *new { |helpSynthPar, switchDur = 10000, switchIndex = 0, helpSynthArgs, pbindArgs, hsIndices, switchOn = false, switchOff = false, set = true, hsStartIndices = \all| + ^this.basicNew(helpSynthPar, switchDur, switchIndex, helpSynthArgs, pbindArgs, hsIndices, switchOn, switchOff, set, hsStartIndices) + .commonInit.addInit; + } + + inputError { |str| + Error("\nWrong PHSpar input - " ++ str ++ "\n").throw + } + + addInputCheck { + var helpSynthArgsMsg = "helpSynthArgs must be collection of: nils or collections of key / value pairs, \n" ++ + "size must equal the number of help synths. \n" ++ + "keys: control names of the corresponding help synth \n" ++ + "values: control values or patterns/streams which produce them \n"; + + helpSynth.isKindOf(HelpSynthPar).not.if { + this.inputError("helpSynthPar must be an instance of HSpar") + }; + ((switchDur.isKindOf(Number) and: { switchDur > 0 }) || switchDur.isKindOf(Pattern) || switchDur.isKindOf(Stream) ).not.if { + this.inputError("switchDur must be number > 0 or a pattern / stream producing numbers") + }; + ((switchIndex.isKindOf(Number) and: { (switchIndex >= 0) && (switchIndex < helpSynth.size) }) || + switchIndex.isKindOf(Pattern) || switchIndex.isKindOf(Stream) ).not.if { + this.inputError("switchIndex must be a possible HS synth index or a pattern / stream producing such indices") + }; + (switchOn.isKindOf(Boolean) || switchOn.isKindOf(Pattern) || switchOn.isKindOf(Stream) ).not.if { + this.inputError("switchOn must be boolean or a pattern / stream producing booleans") + }; + (switchOff.isKindOf(Boolean) || switchOff.isKindOf(Pattern) || switchOff.isKindOf(Stream) ).not.if { + this.inputError("switchOff must be boolean or a pattern / stream producing booleans") + }; + (set.isKindOf(Boolean) || set.isKindOf(Pattern) || set.isKindOf(Stream) ).not.if { + this.inputError("set must be boolean or a pattern / stream producing booleans") + }; + hsStartIndices.miSC_isKindOfPossibleHSstartIndices(helpSynth.size).not.if { + this.inputError("hsStartIndices must be collection of possible help synth indices, \\all or \\none.") + }; + (helpSynthArgs.isNil || + (helpSynthArgs.isKindOf(SequenceableCollection) and: { + (helpSynthArgs.size == helpSynth.size) && + helpSynthArgs.every({|x,i| x.isNil or: { + x.isKindOf(SequenceableCollection) and: { + x.miSC_isPossibleHelpSynthParArgs(helpSynth.controlNames[i]) + } + }}) + } + ) + ).not.if { + this.inputError(helpSynthArgsMsg); + }; + } + + addInit { + hsStartIndices = hsStartIndices.miSC_normalizeHSstartIndices(helpSynth.size); + startPattern = Pbind( + \dur, switchDur, + \index, switchIndex, + \switchOn, switchOn, + \switchOff, switchOff, + \setArgs, set, + \hsStartIndices, hsStartIndices, + \theseArgs, Pswitch1(helpSynth.size.collect({|i| + (helpSynthArgs.isNil or: { helpSynthArgs[i].size == 0 }).if { [\dummyArg, 0] }{ Pclutch(Ptuple(helpSynthArgs[i]), Pkey(\setArgs)) }}), + Pkey(\index)), + \dummy, Pfunc({|e| e.use { + var args = [~index, ~theseArgs, ~switchOn, ~switchOff, ~setArgs, ~hsStartIndices] ; + helpSynth.currentSwitchIndex = ~index; + helpSynth.play(*args); + }; + }), + \type, \rest); + } + + play { |clock, quant, hsPlay| + // dummy arg hsPlay + var warnMsg = "HSpar already playing - use " ++ + "PHSparUse for using a playing or pausing HSpar (or stop and free by Cmd-.)\n"; + (helpSynth.isPlaying && helpSynth.hasJustStartedWithPause.not).if { + warnMsg.warn + }{ + helpSynth.isPHSplaying = true; + ^PHSparPlayer(this).play(clock, quant.asQuant, true); + } + } + + // for use with VarGui + asTask { |clock, quant, hsStop = false, hsPlay = true, switchStop = false, newEnvir = true, removeCtrWithCmdPeriod = true| + var envir, task, player = this, controller; + envir = newEnvir.if { () }{ currentEnvironment }; + task = envir.use { Task { 1e5.wait } }; + controller = SimpleController(task) + .put(\userPlayed, { envir.use { player = player.play(clock: clock, quant: quant.asQuant, hsPlay: hsPlay) } }) + .put(\userStopped, { player.stop(hsStop, switchStop) }); + removeCtrWithCmdPeriod.if { CmdPeriod.doOnce { controller.remove } }; ^task + } +} + diff --git a/Classes/HS/PHelpSynthParPlayer.sc b/Classes/HS/PHelpSynthParPlayer.sc new file mode 100644 index 0000000..df7e661 --- /dev/null +++ b/Classes/HS/PHelpSynthParPlayer.sc @@ -0,0 +1,185 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PHSparPlayer : PHelpSynthParPlayer {} + +PHelpSynthParPlayer : PHelpSynthUsePlayer { + var <>helpSynthPlayer, <>isSwitchPlaying = false; + + *new { arg pHelpSynthPar; + ^super.new(pHelpSynthPar); + } + + play { |clock, quant, hsPlay = true, switchPlay = true, pbindPlay = true, quantBufferTime = 0.2| + var startQuant, demandQuant, receiveQuant, latestQuant, thisClock = clock ?? TempoClock.default, hsPlayIndices, adaptQuant = true; + + (justPlaying.not && justStopping.not).if { + justPlaying = true; + #startQuant, demandQuant, receiveQuant = + helpSynth.makeAdaptedQuants(thisClock, quant.asQuant, adaptQuant, quantBufferTime, switchResumeDelay ); + latestQuant = [startQuant, demandQuant, receiveQuant].sort({|x,y| x.phase <= y.phase}).last; + Task({ justPlaying = false; }).play(thisClock, quant: latestQuant); + + isPlaying.not.if { + ((hsPlay == true) && (switchPlay == true)).not.if { + Error("hsPlay and switchPlay must be true at first call of play - other values at resume only").throw; + }; + // helpSynth.allocBus; + helpSynth.hasJustStartedWithPause.not.if { helpSynth.allocBus }; + + CmdPeriod.add(this); + helpSynth.isListening.not.if { + helpSynth.listen(pHelpSynth.relDemandIndexUserNums.size); + }; + helpSynth.updateDemandIndexOffsets(pHelpSynth); + helpSynth.resetInitSeconds; + + #helpSynthPlayer, helpSynthDemandPlayer, helpSynthReceivePlayer = + [\startPattern, \demandPattern, \receivePattern].collect({|x| pHelpSynth.perform(x).asEventStreamPlayer}); + helpSynth.demandStreams_indexOffsets.put(helpSynthDemandPlayer.originalStream, helpSynth.lastDemandIndexOffset); + helpSynth.receiveStreams_indexOffsets.put(helpSynthReceivePlayer.originalStream, helpSynth.lastDemandIndexOffset); + + helpSynthPlayer.play(clock, quant: startQuant); + isSwitchPlaying = true; + + pbindPlay.if { + helpSynthDemandPlayer.play(clock, quant: demandQuant); + helpSynthReceivePlayer.play(clock, quant: receiveQuant); + isPbindPlaying = true; + }; + + helpSynth.mainPHSplayer = this; + // players are stopped separately with CmdPeriod (free) + [helpSynthPlayer, helpSynthDemandPlayer, helpSynthReceivePlayer].do({|x| CmdPeriod.remove(x)}); + helpSynth.isPHSplaying = true; + isPlaying = true; + + helpSynth.hasJustStartedWithPause.if { helpSynth.hasJustStartedWithPause = false }; + }{ + hsPlayIndices = this.hsInputIndices(hsPlay); + helpSynth.schedRun(true, helpSynth.demandLatency + quantBufferTime, hsPlayIndices); + + (switchPlay && isSwitchPlaying.not).if { helpSynthPlayer.play(clock, quant: startQuant); isSwitchPlaying = true; }; + switchResumeDelay = 0; + + (pbindPlay && isPbindPlaying.not).if { + helpSynthDemandPlayer.play(clock, quant: demandQuant); + helpSynthReceivePlayer.play(clock, quant: receiveQuant); + isPbindPlaying = true; + }; + } + } + } + + hsInputIndices { |hsInput| + var size = helpSynth.size; + case + { hsInput == \switch } { ^[helpSynth.currentSwitchIndex] } + { (hsInput == \none) || (hsInput == false) } { ^[] } + { (hsInput == \all) || (hsInput == true) } { ^(0..size-1) } + { hsInput.isInteger and: { (hsInput < size) && (hsInput >= 0) }} { ^[hsInput] } + { hsInput.isKindOf(Collection) and: + { hsInput.every({|x| x.isInteger and: { (x < size) && (x >= 0) } }) }} { ^hsInput } + { true } { Error.throw("Wrong hsStop / hsPlay input - must be one of: \\all, \\none, \\switch, true, " ++ + "false, a valid HSpar index (integer) or a collection of valid HSpar indices") } + } + + stop { |hsStop = false, switchStop = false, pbindStop = true, addAction| + var clock = helpSynthReceivePlayer.clock, someHSstop, + hsStopIndices, nextDemandAbs, stopAbs, stopBufferTime = 0.15; + + (justPlaying.not && justStopping.not).if { + justStopping = true; + hsStopIndices = this.hsInputIndices(hsStop); + someHSstop = (hsStop != []).if { true }{ false }; + + // stopAbs: basic stopping delay, 8 cases of stopping ... + stopAbs = stopBufferTime * clock.tempo + clock.beats; + + clock.schedAbs(stopAbs, { + (isPbindPlaying && pbindStop).if { + // now look at next demand from delayed stopping point + nextDemandAbs = helpSynthDemandPlayer.nextBeat; + clock.schedAbs(nextDemandAbs, { + (isSwitchPlaying && switchStop).if { + // next switch resume will be delayed by time to next switch from this demand time + switchResumeDelay = (helpSynthPlayer.nextBeat - clock.beats) / clock.tempo; + helpSynthPlayer.stop; + isSwitchPlaying = false; + }{ + switchResumeDelay = 0; + }; + clock.schedAbs((cleanupDelay + max(helpSynth.totalLatency, switchResumeDelay)) * clock.tempo + nextDemandAbs, { + justStopping = false; + }); + someHSstop.if { helpSynth.schedRun(false, helpSynth.demandLatency, hsStopIndices); }; + nil; + }); + helpSynthDemandPlayer.stop; + clock.schedAbs(helpSynth.totalLatency * clock.tempo + stopAbs, { helpSynthReceivePlayer.stop; isPbindPlaying = false; }); + clock.schedAbs((helpSynth.totalLatency + cleanupDelay) * clock.tempo + stopAbs, { addAction.value; nil; }); + }{ + (isSwitchPlaying && switchStop).if { + switchResumeDelay = (helpSynthPlayer.nextBeat - clock.beats) / clock.tempo; + helpSynthPlayer.stop; + isSwitchPlaying = false; + }{ + switchResumeDelay = 0; + }; + clock.schedAbs((cleanupDelay + switchResumeDelay) * clock.tempo + stopAbs, { justStopping = false; }); + someHSstop.if { helpSynth.schedRun(false, helpSynth.demandLatency, hsStopIndices); }; + }; + nil; + }); + }; + } + + pause { |hsStop = true, switchStop = false, pbindStop = true, addAction| + this.stop(hsStop, switchStop, pbindStop, addAction); + } + + cmdPeriod { this.free } + + free { + isPlaying.not.if { + // "Player not playing".warn; + }{ + helpSynthPlayer.stop; + helpSynthDemandPlayer.stop; + helpSynthReceivePlayer.stop; + helpSynth.isPHelpSynthPlaying = false; + isPlaying = false; + isPbindPlaying = false; + isSwitchPlaying = false; + + helpSynth.otherPHSusePlayers.do(_.free); + SystemClock.sched(helpSynth.totalLatency + cleanupDelay, { this.clearBookkeeping; }); + helpSynth.free(helpSynth.totalLatency + cleanupDelay) + }; + CmdPeriod.remove(this); + } +} + + diff --git a/Classes/HS/PHelpSynthParUse.sc b/Classes/HS/PHelpSynthParUse.sc new file mode 100644 index 0000000..9571a85 --- /dev/null +++ b/Classes/HS/PHelpSynthParUse.sc @@ -0,0 +1,210 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PHSparUse : PHelpSynthParUse {} + +PHelpSynthParUse : PHelpSynthUse { + + *basicNew { |helpSynth, pbindArgs, hsIndices| + ^super.basicNew(helpSynth, *pbindArgs).hsIndices_(hsIndices); + } + + *new { |helpSynth, pbindArgs, hsIndices| + ^this.basicNew(helpSynth, pbindArgs, hsIndices).commonInit; + } + + inputError { |str| + Error("\n Wrong PHSparUse input - " ++ str ++ "\n").throw + } + + pbindHelpMsg { + ^"pbindArgs must be collection of the form: [dur1, pbindData1, ... , durN, pbindDataN] \n" ++ + "dur i: duration value or pattern / stream of durations for corresponding Pbind(s) \n" ++ + "pbindData i: a collection of Pbind pairs or a collection of Pbind pair collections, \n" ++ + "defining possibly several Pbinds with same event timing \n" + } + + getReservedKeys { ^[\demandIndex, \timeGrains, \vals, \theseIndices, \switchIndex, \theseVals, \thisVal, \dur, \val, \receiveCleanup] } + + addInputCheck { + var hsIndicesMsg = "hsIndices must be collection of possible hsIndex inputs, \n" ++ + "its size must equal the number of demands in pbindArgs. \n" ++ + "Each hsIndex must either be a possible integer HelpSynth index, one of the symbols \\all, \\switch, \n" ++ + "a collection of unequal HelpSynth indices or a pattern / stream, which produces such items. \n"; + helpSynth.isKindOf(HelpSynthPar).not.if { + this.inputError("helpSynthPar must be an instance of HSpar") + }; + (hsIndices.isNil || (hsIndices.isKindOf(SequenceableCollection) and: { + (hsIndices.size == (pbindArgs.size.div(2))) and: { + hsIndices.miSC_isKindOfPossibleHSindices(pbindArgs.size.div(2), helpSynth.size) + } + }) + ).not.if { + this.inputError(hsIndicesMsg) + }; + } + + makeDemandPattern { |relDemandIndex, demandDur, demandIndexUserNum, demandHSIndices| + ^Pbind( + \dur, demandDur, + \demandHSIndices, demandHSIndices, + \type, \rest, + \dummy, Pfunc({|e| e.use({ + var timeGrains = ((thisThread.seconds - helpSynth.initSeconds) * helpSynth.granularity).round.asInteger, + trigSynth, trigMsgID, trigSynthID, responder, demandIndex, thisDemandIndexOffset, switchIndex, demandNum, x, + oldHSindices, newHSindices, theseHSindices; + + // only one trigger at a time, but it may cover more than one demand + thisDemandIndexOffset = helpSynth.demandStreams_indexOffsets.at(thisThread.miSC_getParent); + demandIndex = thisDemandIndexOffset + relDemandIndex; + + // make entry times_durs + helpSynth.times_durs.at(demandIndex).put(timeGrains, ~dur ); + + // put value in prioirity queue once for each demand index + (helpSynth.timeQueues.at(demandIndex)).put(timeGrains, timeGrains); + + switchIndex = helpSynth.times_switchIndices.at(timeGrains) ?? + (x = helpSynth.currentSwitchIndex; helpSynth.times_switchIndices.put(timeGrains, x); x); + + oldHSindices = helpSynth.times_hsIndices.at(timeGrains); + theseHSindices = case + { ~demandHSIndices.isNil || (~demandHSIndices == \switch) } { [switchIndex] } + { ~demandHSIndices == \all } { (0..(helpSynth.size - 1)) } + { true } { ~demandHSIndices.asArray }; + + helpSynth.times_theseHSindices.at(demandIndex).put(timeGrains, theseHSindices); + + newHSindices = oldHSindices.isNil.if { + theseHSindices.asSet + }{ + theseHSindices.asSet - oldHSindices.asSet; + }; + + demandNum = helpSynth.times_demandNums.removeAt(timeGrains) ?? 0; + // make entry times_hsIndices + helpSynth.times_hsIndices.put(timeGrains, (oldHSindices ++ newHSindices).asArray.sort); + + newHSindices.do({|i| + var trigSynthIndex = thisDemandIndexOffset * helpSynth.size + i; + + trigMsgID = helpSynth.nextTrigMsgID; + trigSynthID = helpSynth.trigSynths.at(trigSynthIndex).nodeID; + responder = helpSynth.makeResponder(trigSynthID, trigMsgID); + responder.add; + + // make entry trigMsgIDs_times + helpSynth.trigMsgIDs_times.put(trigMsgID, timeGrains); + + // make entry trigMsgIDs_hsIndices + helpSynth.trigMsgIDs_hsIndices.put(trigMsgID, i); + + helpSynth.playingHelpSynths.at(i).isNil.if { + Error("trying to poll a value from a help synth not playing, as " ++ + "it hasn't been switched before (maybe set hsStartIndices = \all)").throw; + }{ + helpSynth.server.sendBundle(helpSynth.demandLatency, ["/n_set", trigSynthID, \t_tr, 1], + ["/n_set", trigSynthID, \trigMsgID, trigMsgID]); + } + }); + demandNum = demandNum + 1; + + // make entry times_demandNums + helpSynth.times_demandNums.put(timeGrains, demandNum); }) + }) + ) + } + + makeReceivePatternProtoArgs { |relDemandIndex, repeats| + ^[\demandIndex, + Pstutter(repeats, Pfunc({ |e| e.use { + helpSynth.receiveStreams_indexOffsets.at(thisThread.miSC_getParent.miSC_getParent) + relDemandIndex; + }})).asStream, + \timeGrains, + Pstutter(repeats, Pfunc({ |e| e.use { + this.helpSynth.timeQueues.at(~demandIndex).pop.asInteger; + }})).asStream, + \vals, + Pstutter(repeats, Pfunc({|e| e.use { + helpSynth.times_vals.at(~timeGrains); + }})).asStream, + \theseIndices, + Pstutter(repeats, Pfunc({|e| e.use { + helpSynth.times_theseHSindices.at(~demandIndex).at(~timeGrains); + }})).asStream, + \switchIndex, + Pstutter(repeats, Pfunc({|e| e.use { + helpSynth.times_switchIndices.at(~timeGrains); + }})).asStream, + \theseVals, + Pstutter(repeats, Pfunc({|e| e.use { + ~vals.at(~theseIndices); + }})).asStream, + \thisVal, + Pstutter(repeats, Pfunc({|e| e.use { + ~theseVals.at(0) + }})).asStream, + \dur, + Pstutter(repeats, Pfunc({ |e| e.use { + var maybeDur; + maybeDur = (helpSynth.times_durs.at(~demandIndex)).at(~timeGrains); + maybeDur ?? { Error(" no registered duration at time in ms: " ++ ~timeGrains.asString).throw; } + }})).asStream, + \val, + Pstutter(repeats, Pfunc({ |e| e.use { + var maybeVal, theseDemandIndices; + + maybeVal = ~vals.at(~switchIndex); + maybeVal ?? ~thisVal ?? { Error(" no registered duration at time in ms: " ++ ~timeGrains.asString).throw; } + }})).asStream, + \receiveCleanup, + Pstutter(repeats, Pfunc({ |e| e.use { + var demandNum; + + (helpSynth.times_durs.at(~demandIndex)).removeAt(~timeGrains); + (helpSynth.times_theseHSindices.at(~demandIndex)).removeAt(~timeGrains); + demandNum = helpSynth.times_demandNums.removeAt(~timeGrains); + (demandNum == 1).if { + helpSynth.times_vals.removeAt(~timeGrains); + helpSynth.times_switchIndices.removeAt(~timeGrains); + }{ + helpSynth.times_demandNums.put(~timeGrains, demandNum - 1) + } + }})).asStream + ] + } + + play { |clock, quant| + var warnMsg = "No PHSparPlayer - " ++ + "Playing a PHSparUse needs a PHSpar being played\n"; + + helpSynth.isPHSplaying.not.if { + warnMsg.warn; + }{ + ^PHelpSynthUsePlayer(this).play(clock, quant.asQuant); + } + } +} + diff --git a/Classes/HS/PHelpSynthPlayer.sc b/Classes/HS/PHelpSynthPlayer.sc new file mode 100644 index 0000000..fba77b5 --- /dev/null +++ b/Classes/HS/PHelpSynthPlayer.sc @@ -0,0 +1,146 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +PHSplayer : PHelpSynthPlayer {} + +PHelpSynthPlayer : PHelpSynthUsePlayer { + + *new { arg pHelpSynth; + ^super.new(pHelpSynth); + } + + play { |clock, quant, hsPlay = true, pbindPlay = true, quantBufferTime = 0.2| + var startQuant, demandQuant, receiveQuant, thisClock = clock ?? TempoClock.default, adaptQuant = true, latestQuant, hsStartFunc; + + (justPlaying.not && justStopping.not).if { + justPlaying = true; + #startQuant, demandQuant, receiveQuant = + helpSynth.makeAdaptedQuants(thisClock, quant.asQuant, adaptQuant, quantBufferTime); + latestQuant = [startQuant, demandQuant, receiveQuant].sort({|x,y| x.phase <= y.phase}).last; + Task({ justPlaying = false; }).play(thisClock, quant: latestQuant); + + isPlaying.not.if { + (hsPlay == true).not.if { + Error("hsPlay must be true at first call of play - false at resume only").throw; + }; + helpSynth.hasJustStartedWithPause.not.if { helpSynth.allocBus }; + + CmdPeriod.add(this); + helpSynth.isListening.not.if { + helpSynth.listen(pHelpSynth.relDemandIndexUserNums.size); + }; + helpSynth.updateDemandIndexOffsets(pHelpSynth); + helpSynth.resetInitSeconds; + + hsStartFunc = helpSynth.hasJustStartedWithPause.if { + + { helpSynth.schedRun(true, helpSynth.demandLatency) } + }{ + { helpSynth.play(pHelpSynth.helpSynthArgs ?? [], helpSynth.demandLatency) } + }; + + Task(hsStartFunc).play(clock, quant: startQuant); + + #helpSynthDemandPlayer, helpSynthReceivePlayer = + [\demandPattern, \receivePattern].collect({|x| pHelpSynth.perform(x).asEventStreamPlayer}); + helpSynth.demandStreams_indexOffsets.put(helpSynthDemandPlayer.originalStream, helpSynth.lastDemandIndexOffset); + helpSynth.receiveStreams_indexOffsets.put(helpSynthReceivePlayer.originalStream, helpSynth.lastDemandIndexOffset); + + pbindPlay.if { + helpSynthDemandPlayer.play(clock, quant: demandQuant); + helpSynthReceivePlayer.play(clock, quant: receiveQuant); + isPbindPlaying = true; + }; + + helpSynth.mainPHSplayer = this; + // players are freed separately with CmdPeriod (free) + // [helpSynthDemandPlayer, helpSynthReceivePlayer].do({|x| CmdPeriod.remove(x)}); + helpSynth.isPHSplaying = true; + isPlaying = true; + + helpSynth.hasJustStartedWithPause.if { helpSynth.hasJustStartedWithPause = false }; + }{ + hsPlay.if { Task({ helpSynth.schedRun(true, helpSynth.demandLatency) }).play(clock, quant: startQuant); }; + (pbindPlay && isPbindPlaying.not).if { + helpSynthDemandPlayer.play(clock, quant: demandQuant); + helpSynthReceivePlayer.play(clock, quant: receiveQuant); + isPbindPlaying = true; + } + } + } + } + + stop { |hsStop = false, pbindStop = true, addAction| + var clock = helpSynthReceivePlayer.clock, hsStopLatency, + nextDemandAbs, stopAbs, stopBufferTime = 0.1; + + (justPlaying.not && justStopping.not).if { + justStopping = true; + stopAbs = stopBufferTime * clock.tempo + clock.beats; + hsStopLatency = helpSynth.demandLatency * clock.tempo; + clock.schedAbs(stopAbs, { + (isPbindPlaying && pbindStop).if { + nextDemandAbs = helpSynthDemandPlayer.nextBeat; + hsStop.if { + helpSynth.schedRun(false, nextDemandAbs - clock.beats / clock.tempo + hsStopLatency); + }; + helpSynthDemandPlayer.stop; + clock.schedAbs(helpSynth.totalLatency * clock.tempo + clock.beats, { helpSynthReceivePlayer.stop; isPbindPlaying = false; }); + clock.schedAbs((helpSynth.totalLatency + cleanupDelay) * clock.tempo + clock.beats, { addAction.value; nil; }); + clock.schedAbs((helpSynth.totalLatency + cleanupDelay) * clock.tempo + nextDemandAbs, { justStopping = false; }); + }{ + clock.schedAbs(cleanupDelay * clock.tempo + stopAbs, { justStopping = false; }); + hsStop.if { helpSynth.schedRun(false, hsStopLatency); }; + }; + nil; + }) + } + } + + pause { |hsStop = true, pbindStop = true, addAction| + this.stop(hsStop, pbindStop, addAction); + } + + cmdPeriod { this.free } + + free { + isPlaying.not.if { + // "Player not playing".warn; + }{ + helpSynthDemandPlayer.stop; + helpSynthReceivePlayer.stop; + helpSynth.isPHelpSynthPlaying = false; + isPlaying = false; + isPbindPlaying = false; + + helpSynth.otherPHSusePlayers.do(_.free); + SystemClock.sched(helpSynth.totalLatency + cleanupDelay, { this.clearBookkeeping; }); + helpSynth.free(helpSynth.totalLatency + cleanupDelay); + }; + CmdPeriod.remove(this); + } +} + diff --git a/Classes/HS/PHelpSynthUse.sc b/Classes/HS/PHelpSynthUse.sc new file mode 100644 index 0000000..95e2fa6 --- /dev/null +++ b/Classes/HS/PHelpSynthUse.sc @@ -0,0 +1,230 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PHSuse : PHelpSynthUse {} + +PHelpSynthUse { + var <>helpSynth, <>pbindArgs, <>demandPattern, <>receivePattern, <>relDemandIndexUserNums, <>hsIndices; + + *basicNew { |helpSynth ... pbindArgs| + ^super.new.helpSynth_(helpSynth).pbindArgs_(pbindArgs); + } + + *new { |helpSynth ... pbindArgs| + ^this.basicNew(helpSynth, *pbindArgs).commonInit; + } + + inputError { |str| + Error("\n Wrong PHSuse input - " ++ str ++ "\n").throw + } + + pbindHelpMsg { + ^"pbindArgs (not collected) must be of the form: dur1, pbindData1, ... , durN, pbindDataN \n" ++ + "dur i: duration value or pattern / stream of durations for corresponding Pbind(s) \n" ++ + "pbindData i: a collection of Pbind pairs or a collection of Pbind pair collections, \n" ++ + "defining possibly several Pbinds with same event timing \n" + } + + getReservedKeys { ^[\demandIndex, \timeGrains, \dur, \val, \receiveCleanup] } + + commonInputCheck { + var reservedKeys = this.getReservedKeys; + + (pbindArgs.isKindOf(SequenceableCollection) and: { pbindArgs.miSC_isPossiblePbindArgs }).not.if { + this.inputError(this.pbindHelpMsg) + }; + pbindArgs.miSC_hasNoReservedKeysInPbindArgs(reservedKeys).not.if { + this.inputError("Pbind keys must not contain one of the reserved keys: \n" ++ + reservedKeys.asString ++ "\n\n" ++ this.pbindHelpMsg + ) + }; + } + + addInputCheck { + helpSynth.isKindOf(HelpSynthPar).if { + this.inputError("helpSynth must be an instance of HS") + }; + } + + commonInit { + helpSynth.isKindOf(HelpSynth).not.if { + this.inputError("helpSynth must be an instance of HS or HSpar") + }; + helpSynth.inputCheck.if { this.commonInputCheck.addInputCheck }; + relDemandIndexUserNums = List.new; + # demandPattern, receivePattern = this.makeDemandAndReceivePatterns(pbindArgs); + } + + makeDemandPattern { |relDemandIndex, durPat, demandIndexUserNum, hsIndices| + ^Pbind( + \dur, durPat, + \type, \rest, + \dummy, Pfunc({|e| + var timeGrains = ((thisThread.seconds - helpSynth.initSeconds) * helpSynth.granularity).round.asInteger, + trigSynth, trigMsgID, trigSynthID, demandNum, responder, demandIndex; + + // only one trigger at a time, but it may cover more than one demand + demandIndex = helpSynth.demandStreams_indexOffsets.at(thisThread.miSC_getParent) + relDemandIndex; + trigSynthID = helpSynth.trigSynths.at(demandIndex).nodeID; + + // make entry times_durs + helpSynth.times_durs.at(demandIndex).put(timeGrains, e.use({~dur}) ); + + // put value in prioirity queue once for each demand index + (helpSynth.timeQueues.at(demandIndex)).put(timeGrains, timeGrains); + + // check demand indices of this time + demandNum = helpSynth.times_demandNums.removeAt(timeGrains); + + demandNum.isNil.if { + // no trigMsg yet scheduled for this time + // make responder to expect this trigMsg from the trigger synth from now on + trigMsgID = helpSynth.nextTrigMsgID; + + responder = helpSynth.makeResponder(trigSynthID, trigMsgID); + responder.add; + + // make entry times_demandNums + helpSynth.times_demandNums.put(timeGrains, 1); + + // make entry trigMsgIDs_times + helpSynth.trigMsgIDs_times.put(trigMsgID, timeGrains); + + helpSynth.server.sendBundle(helpSynth.demandLatency, ["/n_set", trigSynthID, \t_tr, 1], + ["/n_set", trigSynthID, \trigMsgID, trigMsgID] + ); + }{ // more than one demand at a time grain, but ... no further msg, update times_demandNums + helpSynth.times_demandNums.put(timeGrains, demandNum + 1); + }; + }) + ) + } + + makeReceivePatternProtoArgs { |relDemandIndex, repeats| + ^[\demandIndex, + Pstutter(repeats, Pfunc({ |e| e.use { + helpSynth.receiveStreams_indexOffsets.at(thisThread.miSC_getParent.miSC_getParent) + relDemandIndex; + }})).asStream, + \timeGrains, + Pstutter(repeats, Pfunc({ |e| e.use { + helpSynth.timeQueues.at(~demandIndex).pop.asInteger; + }})).asStream, + \dur, + Pstutter(repeats, Pfunc({ |e| e.use { + var maybeDur; + maybeDur = (helpSynth.times_durs.at(~demandIndex)).at(~timeGrains); + + maybeDur.isNil.if { + ("WARNING: no registered duration at time in ms: " + ++ ~timeGrains.asString).postln; + ~type = \rest; + }; + maybeDur + }})).asStream, + \val, + Pstutter(repeats, Pfunc({ |e| e.use { + var maybeVal, theseDemandIndices; + maybeVal = (helpSynth.times_vals).at(~timeGrains); + maybeVal.isNil.if { + ("WARNING: no registered value at time in ms: " + ++ ~timeGrains.asString).postln; + }; + maybeVal + }})).asStream, + \receiveCleanup, + Pstutter(repeats, Pfunc({ |e| e.use { + var demandNum; + (helpSynth.times_durs.at(~demandIndex)).removeAt(~timeGrains); + demandNum = helpSynth.times_demandNums.removeAt(~timeGrains); + (demandNum == 1).if { + helpSynth.times_vals.removeAt(~timeGrains); + }{ + helpSynth.times_demandNums.put(~timeGrains, demandNum - 1) + } + }})).asStream + ] + } + + makeDemandAndReceivePatterns { + var demandPatternArgs = List.new, receivePatternArgs = List.new, + durPat, relDemandIndexUserNum, pairsOrArrayOf, demandCounter = 1, receiveCounter = 1, protoArgs; + + pbindArgs.do({|item,i| + (i.even).if { + durPat = item; + pairsOrArrayOf = pbindArgs @ (i+1); + relDemandIndexUserNum = pairsOrArrayOf.every( {|x| x.isKindOf(Array) } ).if { + pairsOrArrayOf.size + }{ + pairsOrArrayOf = [pairsOrArrayOf]; + 1; + }; + relDemandIndexUserNums.add(relDemandIndexUserNum); + demandPatternArgs.add(helpSynth.sequentialSchedShift * demandCounter); + demandPatternArgs.add(this.makeDemandPattern(i.div(2), durPat, + relDemandIndexUserNum, hsIndices.notNil.if { hsIndices[i.div(2)] }{ \switch } )); + demandCounter = demandCounter + 1; + // catch responses for a demand index at a time once + protoArgs = this.makeReceivePatternProtoArgs(i.div(2), pairsOrArrayOf.size); + + relDemandIndexUserNum.do({ |j| + receivePatternArgs.add(helpSynth.sequentialSchedShift * receiveCounter); + receivePatternArgs.add(Pbind(*(protoArgs ++ (pairsOrArrayOf @ j)))); + receiveCounter = receiveCounter + 1; + }); + }; + }); + ^[Ptpar(demandPatternArgs), Ptpar(receivePatternArgs)]; + } + + play { |clock, quant| + var warnMsg = "No PHSplayer - " ++ + "Playing a PHSuse needs a PHS being played\n"; + helpSynth.isPHSplaying.not.if { + warnMsg.warn; + }{ + ^PHelpSynthUsePlayer(this).play(clock, quant.asQuant); + } + } + + // for use with VarGui + asTask { |clock, quant, newEnvir = true, removeCtrWithCmdPeriod = true| + var envir, task, player = this, controller; + envir = newEnvir.if { () }{ currentEnvironment }; + task = envir.use { Task { 1e5.wait } }; + controller = SimpleController(task) + .put(\userPlayed, { + this.helpSynth.isPHelpSynthPlaying.if { + envir.use { player = player.play(clock: clock, quant: quant.asQuant) } + }{ + // PHSusePlayer must wait for PHSplayer + { task.stop; }.defer(0.05); + } + }) + .put(\userStopped, { player.stop }); + removeCtrWithCmdPeriod.if { CmdPeriod.doOnce { controller.remove } }; ^task + } +} + diff --git a/Classes/HS/PHelpSynthUsePlayer.sc b/Classes/HS/PHelpSynthUsePlayer.sc new file mode 100644 index 0000000..b67e928 --- /dev/null +++ b/Classes/HS/PHelpSynthUsePlayer.sc @@ -0,0 +1,114 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +PHSusePlayer : PHelpSynthUsePlayer {} + +PHelpSynthUsePlayer { + var <>pHelpSynth, <>helpSynth, <>helpSynthDemandPlayer, <>helpSynthReceivePlayer, <>trigMsgIDqueue, + <>isPlaying, <>isPbindPlaying, <>demandIndexOffset, <>switchResumeDelay = 0, <>cleanupDelay = 0.01, + <>justPlaying = false, <>justStopping = false; + + *new { arg pHelpSynthUse; + ^super.new.pHelpSynth_(pHelpSynthUse).helpSynth_(pHelpSynthUse.helpSynth) + .trigMsgIDqueue_(PriorityQueue.new) + .isPlaying_(false).isPbindPlaying_(false); + // isPlaying: player already started, also true when pbinds pausing - isPbindPlaying: pbinds are playing + } + + play { |clock, quant, quantBufferTime = 0.2| + var startQuant, demandQuant, receiveQuant, thisClock = clock ?? TempoClock.default, adaptQuant = true, latestQuant; + + (justPlaying.not && justStopping.not).if { + justPlaying = true; + #startQuant, demandQuant, receiveQuant = + helpSynth.makeAdaptedQuants(thisClock, quant.asQuant, adaptQuant, quantBufferTime); + latestQuant = [demandQuant, receiveQuant].sort({|x,y| x.phase <= y.phase}).last; + Task({ justPlaying = false; }).play(thisClock, quant: latestQuant); + + isPlaying.not.if { + CmdPeriod.add(this); + helpSynth.listen(pHelpSynth.relDemandIndexUserNums.size); + helpSynth.updateDemandIndexOffsets(pHelpSynth); + + helpSynthDemandPlayer = pHelpSynth.demandPattern.play(clock, quant: demandQuant); + helpSynthReceivePlayer = pHelpSynth.receivePattern.play(clock, quant: receiveQuant); + helpSynth.demandStreams_indexOffsets.put(helpSynthDemandPlayer.originalStream, helpSynth.lastDemandIndexOffset); + helpSynth.receiveStreams_indexOffsets.put(helpSynthReceivePlayer.originalStream, helpSynth.lastDemandIndexOffset); + + // [helpSynthDemandPlayer, helpSynthReceivePlayer].do({|x| CmdPeriod.remove(x)}); + + helpSynth.otherPHSusePlayers.add(this); + isPlaying = true; + isPbindPlaying = true; + }{ + isPbindPlaying.not.if { + helpSynthDemandPlayer.play(clock, quant: demandQuant); + helpSynthReceivePlayer.play(clock, quant: receiveQuant); + isPbindPlaying = true; + } + }; + } + } + + clearBookkeeping { + trigMsgIDqueue.clear; + } + + stop { |addAction| + var clock = helpSynthReceivePlayer.clock, hsStopLatency, stopAbs, stopBufferTime = 0.1; + + (justPlaying.not && justStopping.not).if { + stopAbs = stopBufferTime * clock.tempo + clock.beats; + isPbindPlaying.if { + justStopping = true; + clock.schedAbs(stopAbs, { + helpSynthDemandPlayer.stop; + clock.schedAbs(helpSynth.totalLatency * clock.tempo + clock.beats, { helpSynthReceivePlayer.stop; isPbindPlaying = false; }); + clock.schedAbs((helpSynth.totalLatency + cleanupDelay) * clock.tempo + clock.beats, { addAction.value; justStopping = false; }); + }); + } + } + } + + pause { |addAction| + this.stop(addAction); + } + + cmdPeriod { this.free } + + free { + isPlaying.not.if { + // "Player not playing".warn; + }{ + helpSynthDemandPlayer.stop; + helpSynthReceivePlayer.stop; + isPlaying = false; + isPbindPlaying = false; + + SystemClock.sched(helpSynth.totalLatency + cleanupDelay, { this.clearBookkeeping; }); + }; + CmdPeriod.remove(this); + } + +} diff --git a/Classes/HS/extHelpSynth.sc b/Classes/HS/extHelpSynth.sc new file mode 100644 index 0000000..f5a37af --- /dev/null +++ b/Classes/HS/extHelpSynth.sc @@ -0,0 +1,79 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ HelpSynth { + newPaused { |pHelpSynth, args, latency| + var synth = Synth.basicNew(helpSynthString, server).register; + playingHelpSynths.put(0, synth); + hasJustStartedWithPause = true; + bus.isNil.if { bus = Bus.control(server, size) }; + isListening.not.if { + this.listen(pHelpSynth.relDemandIndexUserNums.size); + }; + server.sendBundle(latency ?? demandLatency, synth.newMsg(server, + [\i_out, bus.index, \out, bus] ++ (args ?? []) ), synth.runMsg(false)); + // CmdPeriod.remove(synth); + isPlaying = true; + isRunning = false; + ^playingHelpSynths[0] + } +} + ++ PHelpSynth { + newPaused { |args, latency| ^helpSynth.newPaused(this, args, latency); } +} + + ++ HelpSynthPar { + newPaused { |pHelpSynthPar, args, latency| + // args = [ args1, args2, ... ] + var synth; + + hasJustStartedWithPause = true; + bus.isNil.if { bus = Bus.control(server, size) }; + isListening.not.if { + this.listen(pHelpSynthPar.relDemandIndexUserNums.size); + }; + + size.do { |i| + synth = Synth.basicNew(helpSynthString ++ "_" ++ i.asString, server).register; + playingHelpSynths.put(i, synth); + // CmdPeriod.remove(synth); + server.sendBundle(latency ?? demandLatency, synth.newMsg(server, + [\i_out, bus.index + i, \out, bus.index + i] ++ ((args ?? []).at(i)) ?? []), + synth.runMsg(false) + ); + hsRunnings[i] = false; + }; + isPlaying = true; + // isRunning = false; + ^playingHelpSynths; + } + +} + ++ PHelpSynthPar { + newPaused { |args, latency| ^helpSynth.newPaused(this, args, latency); } + +} diff --git a/Classes/HS/extObject.sc b/Classes/HS/extObject.sc new file mode 100644 index 0000000..0a08ed4 --- /dev/null +++ b/Classes/HS/extObject.sc @@ -0,0 +1,67 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// input checks + ++ Object { + + miSC_isKindOfFixedHSindex { |size| + ^(this.isKindOf(Integer) and: { (this >= 0) && (this < size) }) || + [\switch, \all].includes(this.asSymbol) + } + + miSC_isKindOfFixedHSindices { |size| + ^this.miSC_isKindOfFixedHSindex(size) || ( + this.isKindOf(SequenceableCollection) and: { + this.every({ |x| + x.isKindOf(Integer) && (x >= 0) && (x < size) + }) && + (this.asSet.size == this.size) + } + ) + } + + miSC_isKindOfPossibleHSindices { |demandNum, hsNum| + ^this.isKindOf(SequenceableCollection) and: { + (this.size == demandNum) && + this.every({|x| + x.isKindOf(Pattern) || x.isKindOf(Stream) || x.miSC_isKindOfFixedHSindices(hsNum) + }) + } + } + + miSC_isKindOfPossibleHSstartIndices { |size| + ^(this.isKindOf(SequenceableCollection) and: { this.miSC_isIndexSubset(size) }) || + (this.isKindOf(Integer) and: { this <= (size-1) }) || [\none, \all].includes(this.asSymbol) + } + + miSC_normalizeHSstartIndices { |size| // suppose this.miSC_isKindOfPossibleHSstartIndices was true + case + { this == \all }{ ^(0..(size-1)) } + { this == \none }{ ^[] } + { true }{ ^this.asCollection } + } +} + diff --git a/Classes/HS/extSequenceableCollection.sc b/Classes/HS/extSequenceableCollection.sc new file mode 100644 index 0000000..6e7113a --- /dev/null +++ b/Classes/HS/extSequenceableCollection.sc @@ -0,0 +1,89 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// input checks + ++ SequenceableCollection { + + miSC_isKeysAndValues { |requiredKeys| + ^this.size.even and: { this.select({|x,i| i.even }).every({|x| + (x.isKindOf(Symbol) || x.isKindOf(String)) && (requiredKeys.isNil or: { requiredKeys.includes(x.asSymbol) }) + })} + } + + miSC_isPossiblePbindData { + ^this.miSC_isKeysAndValues or: { + this.every({|x| x.isKindOf(SequenceableCollection) and: { x.miSC_isKeysAndValues }}) + } + } + + miSC_isPossiblePbindArgs { + ^this.size.even and: { + this.every({|x,i| + (i.even and: { (x.isKindOf(Number) and: { x > 0 }) or: { x.isKindOf(Pattern) or: { x.isKindOf(Stream) }}}) or: { + i.odd and: { x.isKindOf(SequenceableCollection) and: { x.miSC_isPossiblePbindData } } + } + }) + } + } + + miSC_hasNoReservedKeys { |reservedKeys| // suppose this.miSC_isKeysAndValues was true + ^(this.select({|x,i| i.even }).asSet & (reservedKeys ?? Set[])).size == 0 + } + + miSC_hasNoReservedKeysInPbindData { |reservedKeys| // suppose this.miSC_isPossiblePbindData was true + ^(this.miSC_isKeysAndValues and: { this.miSC_hasNoReservedKeys(reservedKeys) }) or: { + this.every({|x| x.isKindOf(SequenceableCollection) and: { x.miSC_hasNoReservedKeys(reservedKeys) }}) + } + } + + miSC_hasNoReservedKeysInPbindArgs { |reservedKeys| // suppose this.miSC_isPossiblePbindArgs was true + ^this.every({|x,i| + i.even or: { x.miSC_hasNoReservedKeysInPbindData(reservedKeys) } }) + } + + miSC_isPossibleHelpSynthArgs { |requiredKeys| + ^this.miSC_isKeysAndValues(requiredKeys) and: { this.every({|x,i| + (i.odd and: { x.isKindOf(Number) or: { x.isKindOf(Function) }}) || i.even + }) + } + } + + miSC_isPossibleHelpSynthParArgs { |requiredKeys| + ^this.miSC_isKeysAndValues(requiredKeys) and: { this.every({|x,i| + (i.odd and: { x.isKindOf(Number) or: { x.isKindOf(Pattern) or: { x.isKindOf(Stream) }}}) || i.even + }) + } + } + + miSC_areControlRateSynthDefs { + ^this.every({|x| x.children.last.rate == \control }) + } + + miSC_isIndexSubset {|size| + ^(this.asSet.size == this.size) && this.every({|x| x.isKindOf(Integer) && (x >= 0) && (x buf.numFrames).if { + SimpleInitError("wrong inInit/outInit data, size too large").throw + }{ + buf.set(initItem.reverse, buf.numFrames-(initItem.size)) + } + }{ + SimpleInitError( + "wrong inInit/outInit data," ++ + "inconsistent array, see help" + ).throw + } + } + { true }{ + SimpleInitError( + "wrong inInit/outInit data, " ++ + "see help for conventions" + ) + } + }; + + var makeDepthArray = { |depth, buf| + case + { depth.isKindOf(Integer) }{ (0..depth-1) } + { depth.isKindOf(SequenceableCollection) }{ + depth.every(_.isKindOf(Integer)).if { + (depth.size > buf.numFrames).if { + SimpleInitError("wrong inDepth/outDepth, size too large").throw + }{ + depth + } + }{ + SimpleInitError( + "wrong inDepth/outDepth data," ++ + "inconsistent array, see help" + ).throw + } + } + { true }{ + SimpleInitError( + "wrong inDepth/outDepth data, " ++ + "see help for conventions" + ) + } + }; + + [inInit, outInit].do { |init, i| + var buffers = [inBufs, outBufs][i]; + var ioSize = [inBufs.size, outBufs.size][i]; + init.isKindOf(SequenceableCollection).if { + (init.size > ioSize).if { + SimpleInitError( + "wrong inInit/outInit data, " ++ + "size too large, for setting a number of init values " ++ + "per in/out you need double brackets - " + "check conventions in help" + ).throw + }{ + (init.size < ioSize).if { + "".postln; + ("NOTE: " ++ ((i == 0).if { "inInit " }{ "outInit " }) ++ + "size smaller than " ++ + ((i == 0).if { "size of in, " }{ "outSize, " }) ++ + "index wrapping applied").postln; + }; + buffers.do { |bufs, j| + bufs.do { |buf| initSingleBuf.(init.wrapAt(j), buf) } + } + } + }{ + buffers.do { |bufs| + bufs.do { |buf| initSingleBuf.(init, buf) } + } + } + }; + + ^[inDepth, outDepth].collect { |depth, i| + var buffers = [inBufs, outBufs][i]; + var ioSize = [inBufs.size, outBufs.size][i]; + depth.isKindOf(SequenceableCollection).if { + (depth.size > ioSize).if { + SimpleInitError( + "wrong inDepth/outDepth data, " ++ + "size too large, for setting a number of inDepth/outDepth indices " ++ + "per buffer you need double brackets - " + "check conventions in help" + ).throw + }{ + (depth.size < ioSize).if { + "".postln; + ("NOTE: " ++ ((i == 0).if { "inDepth " }{ "outDepth " }) ++ + "size smaller than " ++ + ((i == 0).if { "size of in, " }{ "outSize, " }) ++ + "index wrapping applied").postln; + }; + buffers.collect { |bufs, j| + makeDepthArray.(depth.wrapAt(j), bufs[0]) + } + } + }{ + buffers.collect { |bufs| makeDepthArray.(depth, bufs[0]) } + } + }; + } + + + *ar { |func, in, outSize = 0, inDepth = 1, outDepth = 2, inInit, outInit, + blockSize = 64, blockFactor = 1, graphOrderType = 1, + leakDC = true, leakCoef = 0.995| + + var inSize, inBufsTemp, inBufs, outBufs, iteratedOut, outType, + bufSize, inDepthFlop, outDepthFlop, makeBlockCount, makeFeedSig, + blockCount, bufOffset, outSig, doThis, orderSym; + + // some helper funtions: + // we want be able to handle signals of size 0 as resp. within 'in' and 'out', + // but for data processing it's easier have all in unified nested arrays. + // Preparations are a bit lengthy, but core bufrd/wr loop is short. + + // makeBufs encodes into unified nesting + var makeBufs_0 = { |num, bufSize| { LocalBuf(bufSize).clear } ! max(1, num) }; + var makeBufs = { |num, bufSize| + num.isKindOf(Integer).if { + max(1, num).collect { makeBufs_0.(1, bufSize) } + }{ + num.collect(makeBufs_0.(_, bufSize)) + } + }; + + var getOutType = { |outSize| + outSize.isNumber.if { + (outSize == 0).if { 0 }{ 1 } + }{ + 2 + } + }; + + var outDispatch = { |sig, i, j, type| + (type == 0).if { + sig + }{ + (type == 1).if { + sig[i] + }{ + (sig[i].size == 0).if { sig[i] }{ sig[i][j] } + } + } + }; + + // indexDispatch and shapeSig decode from unified nesting + var indexDispatch = { |sig, i, j| + case + { sig.size == 0 }{ sig } + { sig[i].size == 0 }{ sig[i] } + { true }{ sig[i][j] } + }; + + var shapeSig = { |sig, sizes| + sizes.isKindOf(SequenceableCollection).if { + sizes.collect { |size, j| + (size == 0).if { sig[j][0] }{ sig[j] } + } + }{ + (sizes == 0).if { sig[0][0] }{ sig.collect(_[0]) } + } + }; + + // nils in the depth matrix indicate positions to insert zeros. + // This can save many ugens in the case of multichannel feedback/feedforward + // with differentiated lookback size. + + var fillWithNils = { |array| + var maxSize = array.collect(_.size).maxItem; + array.collect(_.extend(maxSize, nil)) + }; + + // lookback beyond blockSize + + // basically all the same in the core procedure below, + // but the buffer indices to be used need a looping offset + + makeBlockCount = { + Main.versionAtLeast(3, 9).if { + Duty.kr(ControlDur.ir, 0, Dseq((0..blockFactor-1), inf)) + }{ + // correct init bug for older SC version + Duty.kr(ControlDur.ir, 0, Dseq((0..blockFactor-1), inf) - 1 % blockFactor) + } + }; + blockCount = (blockFactor > 1).if { makeBlockCount.() }{ 0 }; + bufOffset = blockCount * blockSize; + + inSize = in.isKindOf(SequenceableCollection).if { in.collect(_.size) }{ in.size }; + bufSize = blockSize * blockFactor; + + inBufsTemp = makeBufs.(inSize, bufSize); + inBufs = makeBufs.(inSize, bufSize); + outBufs = makeBufs.(outSize, bufSize); + outType = getOutType.(outSize); + + #inDepth, outDepth = this.checkInits(inBufs, outBufs, inInit, outInit, inDepth, outDepth); + + // depths were passed per signal, but we rather want to iterate over lookback indices + + inDepthFlop = fillWithNils.(inDepth).flop; + outDepthFlop = fillWithNils.(outDepth).flop; + + + // trick for buffering feedforward audio signals: + // store in temporary buffers first and write with kr to 'real' buffers thereafter. + // That way we can use the 'real' buffers in the iteration process below, + // which is based on the order of the synthdef graph. + + // the temporary buffers cannot be used for reference to feedforward data in the + // iteration over blockSize, as they are overriden immediately. + + // same structure to bring encoded feedback and feedforward signals + // to desired format for func's 'in' and 'out' + + makeFeedSig = { |depthFlop, bufs, sizes, i| + var sig; + depthFlop.collect { |depths, j| + sig = bufs.collect { |buf, k| + depths[k].isNil.if { [0] }{ + BufRd.kr(1, buf, (i-depths[k]) % bufSize) + } + }; + shapeSig.(sig, sizes); + } + }; + + + // begin of core definition + // 3 versions of implementation + + // with graphOrderType = 1 (default), buffer reading and writing is forced + // to its desired order with the use of sum and 1 + var l = bufOffset + i; + + // prepare data from 'in' signals + // force writers after temporary writer + inBufs.do { |bufs, j| + bufs.do { |buf, k| + doThis = orderSym.applyTo( + doThis, + BufWr.kr(BufRd.kr(1, inBufsTemp[j][k], l), buf, l) + ) + } + }; + + // here comes actual fb/ff relation into play + // it can refer to former 'in'/'out' values (see makeFeedSig definition) + + iteratedOut = func.value( + makeFeedSig.(inDepthFlop, inBufs, inSize, l), + makeFeedSig.(outDepthFlop, outBufs, outSize, l), + i + ); + + // the calculated next sample(s) written to buffer(s) + outBufs.do { |bufs, j| + bufs.do { |buf, k| + doThis = orderSym.applyTo( + doThis, + BufWr.kr(outDispatch.(iteratedOut, j, k, outType), buf, l) + ) + } + }; + }; + // move through buffers(s), make ar signal + // ' 1 + var l = bufOffset + i; + + // prepare data from 'in' signals + inBufs.collect { |bufs, j| + bufs.collect { |buf, k| + BufWr.kr(BufRd.kr(1, inBufsTemp[j][k], l), buf, l) + } + }; + // here comes actual fb/ff relation into play + // it can refer to former 'in'/'out' values (see makeFeedSig definition) + iteratedOut = func.value( + makeFeedSig.(inDepthFlop, inBufs, inSize, l), + makeFeedSig.(outDepthFlop, outBufs, outSize, l), + i + ); + // the calculated next sample(s) written to buffer(s) + outBufs.collect { |bufs, j| + bufs.collect { |buf, k| + BufWr.kr(outDispatch.(iteratedOut, j, k, outType), buf, l) + } + } + }; + // move through buffers(s), make ar signal + outSig = BufRd.ar(1, shapeSig.(outBufs, outSize), Phasor.ar(0, 1, 0, bufSize)); + } + + { true }{ SimpleInitError("wrong graphOrderType, must be 0, 1 or 2, see help").throw }; + + ^leakDC.if { LeakDC.ar(outSig, leakCoef) }{ outSig } + } + + +// The kr variant provides a nearly identical interface, +// but without args blockSize and blockFactor, +// therefore the implementation, although much more straight, +// has subtle differences: +// buffer sizes are taken from depth params, +// in samples don't have to be buffered temporarily +// instead inBufs have to be rewritten, +// also some helper functions are slightly different. + + +*kr { |func, in, outSize = 0, inDepth = 1, outDepth = 2, inInit, outInit, + graphOrderType = 1, leakDC = true, leakCoef = 0.995| + + var inSize, inBufs, outBufs, iteratedOut, outType, unshapedOut, + inDepthFlop, outDepthFlop, makeFeedSig, blockCount, shapedOutSig, + outSig, doThis, orderSym; + + // some helper funtions: + // we want be able to handle signals of size 0 as resp. within 'in' and 'out', + // but for data processing it's easier have all in unified nested arrays. + // Preparations are a bit lengthy, but core bufrd/wr loop is short. + + // makeBufs encodes into unified nesting + var makeBufs_0 = { |num, bufSize| { LocalBuf(bufSize).clear } ! max(1, num) }; + + + // different in the kr case, must take bufSizes from depth + var makeBufs = { |num, depth| + num.isKindOf(Integer).if { + max(1, num).collect { |i| + makeBufs_0.(1, depth.miSC_maybeWrapAt(i).asArray.maxItem) + } + }{ + num.collect { |x, i| + makeBufs_0.(x, depth.miSC_maybeWrapAt(i).asArray.maxItem) + } + } + }; + + var getOutType = { |outSize| + outSize.isNumber.if { + (outSize == 0).if { 0 }{ 1 } + }{ + 2 + } + }; + + var outDispatch = { |sig, i, j, type| + (type == 0).if { + sig + }{ + (type == 1).if { + sig[i] + }{ + (sig[i].size == 0).if { sig[i] }{ sig[i][j] } + } + } + }; + + // indexDispatch and shapeSig decode from unified nesting + var indexDispatch = { |sig, i, j| + case + { sig.size == 0 }{ sig } + { sig[i].size == 0 }{ sig[i] } + { true }{ sig[i][j] } + }; + + var shapeSig = { |sig, sizes| + sizes.isKindOf(SequenceableCollection).if { + sizes.collect { |size, j| + (size == 0).if { sig[j][0] }{ sig[j] } + } + }{ + (sizes == 0).if { sig[0][0] }{ sig.collect(_[0]) } + } + }; + + // nils in the depth matrix indicate positions to insert zeros. + // This can save many ugens in the case of multichannel feedback/feedforward + // with differentiated lookback size. + + var fillWithNils = { |array| + var maxSize = array.collect(_.size).maxItem; + array.collect(_.extend(maxSize, nil)) + }; + + // blockCount works different here from ar: + // it counts absolutely, modulo is taken per Buffer + + blockCount = Main.versionAtLeast(3, 9).if { + Duty.kr(ControlDur.ir, 0, Dseries(0, 1, inf)) + }{ + // correct init bug for older SC version + Duty.kr(ControlDur.ir, 0, Dseries(0, 1, inf) - 1) + }; + + inSize = in.isKindOf(SequenceableCollection).if { in.collect(_.size) }{ in.size }; + + // convention: indices start from 0 and increase with time, + // thus an init array is stored in reverse order (see checkInits) + inBufs = makeBufs.(inSize, inDepth); + outBufs = makeBufs.(outSize, outDepth); + + outType = getOutType.(outSize); + + #inDepth, outDepth = this.checkInits(inBufs, outBufs, inInit, outInit, inDepth, outDepth); + + // depths were passed per signal, but we rather want to iterate over lookback indices + + inDepthFlop = fillWithNils.(inDepth).flop; + outDepthFlop = fillWithNils.(outDepth).flop; + + // same structure to bring encoded feedback and feedforward signals + // to desired format for func's 'in' and 'out' + + // differs from ar ! + makeFeedSig = { |depthFlop, ioBufs, sizes, blockCount| + var sig; + depthFlop.collect { |depths, j| + sig = ioBufs.collect { |bufs, k| + depths[k].isNil.if { [0] }{ + // differs from ar here + BufRd.kr(1, bufs, (blockCount-depths[k]) % (bufs.collect(_.numFrames))) + } + }; + shapeSig.(sig, sizes); + } + }; + + + // begin of core definition + // 3 versions of implementation + + // with graphOrderType = 1 (default), buffer reading and writing is forced + // to its desired order with the use of sum and 1) and: { argList0.flat.any(_.isNumber.not) }).if { + err = SimpleInitError("initial ODE Function values have to be " ++ + "calculated in language and there are non-number items (UGens) " ++ + "contained in argList. Either take an intType where initial " ++ + "calculation is not necessary (e.g. \\sym2, \\sym4, etc.) or pass an " + "additional argList0 arg with numbers only").class_("Fb1_ODE").throw; + }; + + (stepDepth > 1).if { + var templateString = + "A multi-step procedure is selected, so initial ODE solution " ++ + "approximations have to be calculated in language, "; + var rateString = (rate == \audio).if { "sampleRate" }{ "controlRate" }; + + // for multi-step procedures we need the first values (resp. arrays of values) + dt0 = dt0 ?? { + var s = Server.default; + var dtRate = s.notNil.if { + (rate == \audio).if { + s.sampleRate + }{ + s.sampleRate / s.options.blockSize + } + }; + + dtRate.isNil.if { + err = SimpleInitError(templateString ++ + "but no default server is found, so " ++ + "an assumption has to be made for first delta t, " ++ + "please define dt0 in secs, recommended: " ++ + "tMul at start / planned " ++ rateString).class_("Fb1_ODE").throw; + }{ + tMul.isNumber.not.if { + err = SimpleInitError(templateString ++ + "but there are non-number items (UGens) contained in tMul, " ++ + "please define dt0 in secs, recommended: " ++ + "tMul at start / planned " ++ rateString).class_("Fb1_ODE").throw; + }{ + (templateString ++ + "but dt0 is not defined, " ++ + "tMul divided by default server's " ++ rateString ++ + " is taken instead." + ).postln; + tMul / dtRate + } + } + }; + }{ + // also for single-step procedures we must evaluate the ODE Function for x_d intTypes + // but for stepDepth == 1 dt0 is not used, no problem if it's a UGen or nil + }; + + + outInit = odeDef.makeOutInit(intType, init_intType, t0, y0, dt0, argList0, true); + + (rate == \audio).if { + op = \ar; + + // we have to build the Fb1 function in a way that it reads ar args. + // convention: composeArIn first (indices possibly defined in compose Function), + // then detected ar args from argList, then the integrated time (Sweep) and tMul (if ar) + + // This "external" time integration is absolutely necessary as + // a binary operator summing of dts leads to drifts !! + + composeArIn = composeArIn.asArray; + tSum = t0 + Sweep.ar(0, tMul); + + argListFlatAr = argList.flatten.select(_.miSC_isAr); + + fb1_in = composeArIn ++ argListFlatAr ++ tSum ++ (tMul.miSC_isAr.if { tMul }); + + fb1_inDepth = (1 ! composeArIn.size) ++ + (1 ! argListFlatAr.size) ++ 2 ++ (tMul.miSC_isAr.if { 1 }); + + fb1_inInit = (nil ! composeArIn.size) ++ + (nil ! argListFlatAr.size) ++ t0 ++ (tMul.miSC_isAr.if { [nil] }); + + // used in the Fb1 Function + basicDelta = SampleDur.ir; + + // in this Function integration method and ODE Function are composed + // it will get passed the out arg from the Fb1 Function + fb1_intFunc = odeDef.dispatchIntFunc(intType); + + + // core: everything packed into the Fb1 function, which contructs the graph iteratively + fb1_func = { |in, out| + var lastDt, count = composeArIn.size - 1; + composeIns = composeArIn.size.collect { |i| in[0][i] }; + + #argIns, count = argList.miSC_adaptFb1ArgList(in[0], count); + + tSumInOld = in[1][count + 1]; + tMulIn = tMul.miSC_isAr.if { in[0][count + 2] }{ tMul }; + + fb1_intFunc.(out, tSumInOld, basicDelta * tMulIn, argIns) + .miSC_fb1_perform(compose, composeIns, size, outSize); + }; + + // wrong blockSize can lead to confusion, better check + sBlockSize = Server.default.notNil.if { + Server.default.options.blockSize + }; + + blockSize.isNil.if { + sBlockSize.isNil.if { + err = SimpleInitError( + "no default blockSize detected and no blockSize passed") + .class_("Fb1_ODE").throw; + }{ + "".postln; + ("Fb1_ODE: taking default server's blockSize " ++ sBlockSize.asString).postln; + "".postln; + blockSize = sBlockSize; + } + }{ + (blockSize.isInteger and: { blockSize.isPowerOfTwo }).if { + (sBlockSize != blockSize).if { + sBlockSize.notNil.if { + "".postln; + ("blockSize " ++ blockSize.asString ++ "passed to Fb1_ODE " ++ + "unequal to default Server's blockSize " ++ + sBlockSize.asString ++ " - intended ?").warn; + "".postln; + }{ + "".postln; + ("Fb1_ODE: no default blockSize detected, " ++ + "taking passed blockSize " ++ blockSize.asString).warn; + "".postln; + } + } + }{ + err = SimpleInitError("blockSize must be integer power of 2") + .class_("Fb1_ODE").throw; + } + }; + + // blockFactor has to be chosen correctly, + // especially relevant for small blockSizes: + + // e.g. for blockSize 4 a blockFactor of 1 is sufficient + // only for stepDepth 1-4; + // for blockSize 1 we need a blockFactor equal to stepDepth, + // in general: + + blockFactor = (stepDepth - 1).div(blockSize) + 1; + + sig = Fb1.ar(fb1_func, fb1_in, + outSize: outSize, + inDepth: fb1_inDepth, + outDepth: outDepth, + inInit: fb1_inInit, + outInit: outInit, + blockSize: blockSize, + blockFactor: blockFactor, + graphOrderType: graphOrderType, + leakDC: leakDC, + leakCoef: leakCoef + ); + + }{ + op = \kr; + + // things are more straight here + // still "external" time integration is better ! + tSum = t0 + Sweep.kr(0, tMul); + + // used in the Fb1 Function + basicDelta = ControlDur.ir; + + // in this Function integration method and ODE Function are composed + // it will get passed the out arg from the Fb1 Function + fb1_intFunc = odeDef.dispatchIntFunc(intType); + + // core: everything packed into the Fb1 function, which contructs the graph iteratively + fb1_func = { |in, out| + fb1_intFunc.(out, in[1] /* last time */, basicDelta * tMul, argList) + .miSC_fb1_perform(compose, [], size, outSize); + }; + + // pass integrated time via 'in' as we need last one + sig = Fb1.kr(fb1_func, tSum, + outSize: outSize, + inDepth: 2, + outDepth: outDepth, + inInit: t0, + outInit: outInit, + graphOrderType: graphOrderType, + leakDC: leakDC, + leakCoef: leakCoef + ) + }; + + // optional default scaling (makes sense for systems like Lorenz) + + outScale = withOutScale.if { + [odeDef.outScale, odeDef.diffOutScale] + }{ + [1, 1] + }; + + // options for derivation and time return + + sig = (sig[..size-1] * outScale[0]) ++ + (withDiffChannels.if { + sig[rawIntSize-size..rawIntSize-1] * outScale[1] + }{ [] }) ++ + (withTimeChannel.if { tSum }{ [] }); + + sig = (outSize == 1).if { sig[0] }{ sig }; + + // might be necessary + ^sig 1).if { + z0 = y0 ++ this.(nil, t0, y0, *args); + }; + withTime.if { z0 = z0 ++ [t0] }; + ^z0 + } + + makeOutInit { |fb1_intType, init_intType = \sym8, t0, y0, dt, args, withTime = true| + var z0 = this.makeFirstOutInit(fb1_intType, t0, y0, args, withTime); + var depth = Fb1_ODEintdef.at(fb1_intType).stepDepth; + + z0 = (depth == 1).if { + [z0] + }{ + // produces startValues for multi-step procedures like + // Adams-Bashforth und Adams-Moulton + this.nextN(depth - 1, init_intType, t0, z0, dt, args, withTime, true) + }; + // the result is reversed (last values first) and flopped + // in order to be prepared as Fb1 outInit arg + ^z0.reverse.flop + } + + getIntSize { |intType| + ^size * Fb1_ODEintdef.at(intType).sizeFactor; + } + + dispatchIntFunc { |intType| + var multiStep = Fb1_ODEintdef.at(intType).stepDepth > 1; + var n = this.getIntSize(intType); + var comp = this.compose(intType); // step Function from ODE and intType + var size = this.size; + + // this Function is used inside Fb1's Function + // z gets the 'out' arg + + // oldT comes from the external time integrator (Sweep), + // which is necessary to avoid drifts that occur with + // plain summation via binary operators + + ^{ |z, oldT, dt, argList| + var y; + // multi-step integration: need previous arrays from Fb1 'out' + // one-step integration: need only one previous array from Fb1 'out' + multiStep.if { y = z.drop(1) }{ y = z[1] }; + comp.(oldT, y, dt, size, *argList); + } + } + +} + diff --git a/Classes/Nonlinear/Fb1_ODEintdef.sc b/Classes/Nonlinear/Fb1_ODEintdef.sc new file mode 100644 index 0000000..921b829 --- /dev/null +++ b/Classes/Nonlinear/Fb1_ODEintdef.sc @@ -0,0 +1,606 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +Fb1_ODEintdef { + + // container for stepper Functions representing numeric ODE solvers + // composition of stepper with ODE Function gives the Function to be used within Fb1 + + classvar all, initKeys; + + var 1 + // not to be confused with single-step procedures with sub-steps (like Runge-Kutta) + + // sizeFactor indicates whether ODE function values are buffered + // for some procedures this is necessary (ab, abm, pec, pece etc.) + // for others there exist procedures without and with buffering (e.g. so there is rk3 and rk3_d) + + *new { |name, function, stepDepth = 1, sizeFactor = 1| + ^super.newCopyArgs(name, function, stepDepth, sizeFactor) + .initFb1_ODEintdef(name); + } + + *at { |key| ^all.at(key) } + + *keys { |key| ^all.keys.copy } + + *remove { |key| initKeys.includes(key).not.if { all.put(key, nil) } } + + // remove all added Fb1_ODEintdefs + *reset { all.do { |x| this.remove(x.name) } } + + *postAll { + var nameStrings = (this.keys.asArray.collect { |x| x.asString }).sort; + "\nCurrent Fb1_ODEintdefs: \n".postln; + nameStrings.do { |str| str.postln; }; + "".postln; + } + + *initClass { + var symplecticOp; + + all = IdentityDictionary.new; + + // constructors need unified args, + // thus time and size are always defined and not necessarily needed + + // y is expected to be an array (state vector from the ODE system) + // for muiltistep procedures it expects + // an array of arrays (including previous states) + + // the _d variants produce channel(s) for the differential (resp. ODE function values) + // whenever the main integration doesn't need to employ such anyway + + // It's recommended to work with symplectic integrators + // as they are better for long-time stability, which is necessary for oscillatory solutions! + // Also it's easy to get symplectic integration of higher order, + // simply adapt for order 2k by dividing dt and repeat operation + + symplecticOp = { |order, odeDef, t, y, dt, size, args| + var newArgs = y.copy, yMid = y.copy, yNew = 0!size, or = 1/order; + + or = 1/order; + + div(order, 2).do { |k| + (k > 0).if { + newArgs = yNew.copy; + yMid = yNew.copy; + }; + for(0, size-1, { |i| + (i > 0).if { newArgs[i-1] = yMid[i-1] }; + yMid[i] = odeDef.(i, t, newArgs, *args) * dt * or + yMid[i]; + }); + for(size-1, 0, { |i| + (i + 1 < size).if { newArgs[i+1] = yNew[i+1] }; + yNew[i] = odeDef.(i, t, newArgs, *args) * dt * or + yMid[i]; + }); + }; + yNew + }; + + Fb1_ODEintdef(\sym2, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(2, odeDef, t, y, dt, size, args); + }, 1, 1); + + + // in the '_d' variants y has doubled size but that doesn't matter as + // size is passed to symplecticOp + Fb1_ODEintdef(\sym2_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(2, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym4, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(4, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym4_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(4, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym6, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(6, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym6_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(6, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym8, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(8, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym8_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(8, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym12, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(12, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym12_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(12, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym16, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(16, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym16_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(16, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym32, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(32, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym32_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(32, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + Fb1_ODEintdef(\sym64, + { |odeDef, t, y, dt, size ... args| + symplecticOp.(64, odeDef, t, y, dt, size, args); + }, 1, 1); + + + Fb1_ODEintdef(\sym64_d, + { |odeDef, t, y, dt, size ... args| + var yNew = symplecticOp.(64, odeDef, t, y, dt, size, args); + var fNew = fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + // Euler simple (1-step RK), not recommended ! + Fb1_ODEintdef(\eu, + { |odeDef, t, y, dt, size ... args| + odeDef.(nil, t, y, *args) * dt + y + }, 1, 1); + + Fb1_ODEintdef(\eu_d, + { |odeDef, t, y, dt, size ... args| + var yy, ff, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + yNew = ff * dt + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + // Euler modified (2-step RK) + Fb1_ODEintdef(\eum, + { |odeDef, t, y, dt, size ... args| + var yy = odeDef.value(nil, t, y, *args) * dt * 0.5 + y; + odeDef.(nil, dt * 0.5 + t, yy, *args) * dt + y; + }, 1, 1); + + Fb1_ODEintdef(\eum_d, + { |odeDef, t, y, dt, size ... args| + var yy, ff, z, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + z = ff * dt * 0.5 + yy; + yNew = odeDef.(nil, dt * 0.5 + t, z, *args) * dt + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + // Euler improved (Heun), 2-step RK + Fb1_ODEintdef(\eui, + { |odeDef, t, y, dt, size ... args| + var e = odeDef.(nil, t, y, *args); + var z = e * dt + y; + (odeDef.(nil, t + dt, z, *args) + e) * dt * 0.5 + y + }, 1, 1); + + Fb1_ODEintdef(\eui_d, + { |odeDef, t, y, dt, size ... args| + var yy, ff, z, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + z = ff * dt + yy; + yNew = (odeDef.(nil, t + dt, z, *args) + ff) * dt * 0.5 + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + // variants of prediction-evaluation-correction + // using explicit Euler and trapezoidal rule + Fb1_ODEintdef(\pec, + { |odeDef, t, y, dt, size ... args| + var tn = t + dt; + var y0 = y[0..size-1]; + var y1 = y[size..2*size-1]; + var p = y1 * dt + y0; + var pe = odeDef.(nil, tn, p, *args); + var pec = (y1 + pe) * dt * 0.5 + y0; + pec ++ pe + }, 1, 2); + + Fb1_ODEintdef(\pecec, + { |odeDef, t, y, dt, size ... args| + var tn = t + dt; + var y0 = y[0..size-1]; + var y1 = y[size..2*size-1]; + var p = y1 * dt + y[0..size-1]; + var pe = odeDef.(nil, tn, p, *args); + var pec = (y1 + pe) * dt * 0.5 + y0; + var pece = odeDef.(nil, tn, pec, *args); + var pecec = (y1 + pece) * dt * 0.5 + y0; + pecec ++ pece + }, 1, 2); + + Fb1_ODEintdef(\pece, + { |odeDef, t, y, dt, size ... args| + var tn = t + dt; + var y0 = y[0..size-1]; + var y1 = y[size..2*size-1]; + var p = y1 * dt + y0; + var pe = odeDef.(nil, tn, p, *args); + var pec = (y1 + pe) * dt * 0.5 + y0; + var pece = odeDef.(nil, tn, pec, *args); + pec ++ pece + }, 1, 2); + + Fb1_ODEintdef(\pecece, + { |odeDef, t, y, dt, size ... args| + var tn = t + dt; + var y0 = y[0..size-1]; + var y1 = y[size..2*size-1]; + var p = y1 * dt + y0; + var pe = odeDef.(nil, tn, p, *args); + var pec = (y1 + pe) * dt * 0.5 + y0; + var pece = odeDef.(nil, tn, pec, *args); + var pecec = (y1 + pece) * dt * 0.5 + y0; + var pecece = odeDef.(nil, tn, pecec, *args); + pecec ++ pecece + }, 1, 2); + + + // Runge-Kutta 3-step + Fb1_ODEintdef(\rk3, + { |odeDef, t, y, dt, size ... args| + var k1 = odeDef.(nil, t, y, *args); + var k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + y, *args); + var k3 = odeDef.(nil, dt + t, dt * 2 * k2 - (dt * k1) + y, *args); + (k1 + (4 * k2) + k3) * dt / 6 + y + }, 1, 1); + + Fb1_ODEintdef(\rk3_d, + { |odeDef, t, y, dt, size ... args| + var k1, k2, k3, yy, ff, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + k1 = ff; + k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + yy, *args); + k3 = odeDef.(nil, dt + t, dt * 2 * k2 - (dt * k1) + yy, *args); + yNew = (k1 + (4 * k2) + k3) * dt / 6 + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + // Runge-Kutta 3-step (Heun) + Fb1_ODEintdef(\rk3h, + { |odeDef, t, y, dt, size ... args| + var k1 = odeDef.(nil, t, y, *args); + var k2 = odeDef.(nil, dt / 3 + t, k1 * dt / 3 + y, *args); + var k3 = odeDef.(nil, dt * 2/3 + t, dt * (2/3) * k2 + y, *args); + (3 * k3 + k1) * dt * 0.25 + y + }, 1, 1); + + Fb1_ODEintdef(\rk3h_d, + { |odeDef, t, y, dt, size ... args| + var k1, k2, k3, yy, ff, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + k1 = ff; + k2 = odeDef.(nil, dt / 3 + t, k1 * dt / 3 + yy, *args); + k3 = odeDef.(nil, dt * 2/3 + t, dt * (2/3) * k2 + yy, *args); + yNew = (3 * k3 + k1) * dt * 0.25 + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + // Runge-Kutta 4-step (classical) + Fb1_ODEintdef(\rk4, + { |odeDef, t, y, dt, size ... args| + var k1 = odeDef.(nil, t, y, *args); + var k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + y, *args); + var k3 = odeDef.(nil, dt * 0.5 + t, k2 * dt * 0.5 + y, *args); + var k4 = odeDef.(nil, dt + t, k3 * dt + y, *args); + ((k2 + k3) * 2 + k1 + k4) * dt / 6 + y + }, 1, 1); + + Fb1_ODEintdef(\rk4_d, + { |odeDef, t, y, dt, size ... args| + var k1, k2, k3, k4, yy, ff, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + k1 = ff; + k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + yy, *args); + k3 = odeDef.(nil, dt * 0.5 + t, k2 * dt * 0.5 + yy, *args); + k4 = odeDef.(nil, dt + t, k3 * dt + yy, *args); + yNew = ((k2 + k3) * 2 + k1 + k4) * dt / 6 + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); + + + // Adams-Bashforth multi-step + // ab Functions are not optimized for iterated language use + // doesn't matter though if merged into the UGenGraphFunction + + // y expects array of arrays ! + // y[0] contains previous y and and previous function values + + Fb1_ODEintdef(\ab2, + { |odeDef, t, y, dt, size ... args| + var yy, ff, yNew, fNew; + yy = y.collect(_[0..size-1]); // prev y + ff = y.collect(_[size..2*size-1]); // prev function values + yNew = (3 * ff[0] - ff[1]) * dt * 0.5 + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 2, 2); + + Fb1_ODEintdef(\ab3, + { |odeDef, t, y, dt, size ... args| + var yy, ff, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + yNew = (23/12 * ff[0] - (16/12 * ff[1]) + (5/12 * ff[2])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 3, 2); + + Fb1_ODEintdef(\ab4, + { |odeDef, t, y, dt, size ... args| + var yy, ff, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + yNew = (55/24 * ff[0] - (59/24 * ff[1]) + (37/24 * ff[2]) - + (9/24 * ff[3])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 4, 2); + + Fb1_ODEintdef(\ab5, + { |odeDef, t, y, dt, size ... args| + var yy, ff, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + yNew = (1901/720 * ff[0] - (2774/720 * ff[1]) + (2616/720 * ff[2]) - + (1274/720 * ff[3]) + (251/720 * ff[4])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 5, 2); + + Fb1_ODEintdef(\ab6, + { |odeDef, t, y, dt, size ... args| + var yy, ff, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + yNew = (4277/1440 * ff[0] - (7923/1440 * ff[1]) + (9982/1440 * ff[2]) - + (7298/1440 * ff[3]) + (2877/1440 * ff[4]) - (475/1440 * ff[5])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 6, 2); + + // Adams-Bashforth-Moulton predictor corrector + // theory suggests to combine k-step predictor with (k-1) step corrector + // y expects array of arrays ! + // y[0] contains previous y and and previous function values + + Fb1_ODEintdef(\abm21, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); // prev y + ff = y.collect(_[size..2*size-1]); // prev function values + p = (3 * ff[0] - ff[1]) * dt * 0.5 + yy[0]; // Adams-Bashforth predictor + fp = odeDef.(nil, t + dt, p, *args); + yNew = (fp + ff[0]) * dt * 0.5 + yy[0]; // Adams-Moulton corrector + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 2, 2); + + Fb1_ODEintdef(\abm22, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (3 * ff[0] - ff[1]) * dt * 0.5 + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((5/12 * fp) + (8/12 * ff[0]) - (ff[1]/12)) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 2, 2); + + Fb1_ODEintdef(\abm32, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (23/12 * ff[0] - (4/3 * ff[1]) + (5/12 * ff[2])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((5/12 * fp) + (2/3 * ff[0]) - (ff[1]/12)) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 3, 2); + + Fb1_ODEintdef(\abm33, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (23/12 * ff[0] - (4/3 * ff[1]) + (5/12 * ff[2])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((3/8 * fp) + (19/24 * ff[0]) - (5/24 * ff[1]) + (ff[2]/24)) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 3, 2); + + Fb1_ODEintdef(\abm43, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (55/24 * ff[0] - (59/24 * ff[1]) + (37/24 * ff[2]) - + (3/8 * ff[3])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((3/8 * fp) + (19/24 * ff[0]) - (5/24 * ff[1]) + (ff[2]/24)) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 4, 2); + + Fb1_ODEintdef(\abm44, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (55/24 * ff[0] - (59/24 * ff[1]) + (37/24 * ff[2]) - + (3/8 * ff[3])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((251/720 * fp) + (646/720 * ff[0]) - (264/720 * ff[1]) + + (106/720 * ff[2]) - (19/720 * ff[3])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 4, 2); + + Fb1_ODEintdef(\abm54, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (1901/720 * ff[0] - (2774/720 * ff[1]) + (2616/720 * ff[2]) - + (1274/720 * ff[3]) + (251/720 * ff[4])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((251/720 * fp) + (646/720 * ff[0]) - (264/720 * ff[1]) + + (106/720 * ff[2]) - (19/720 * ff[3])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 5, 2); + + Fb1_ODEintdef(\abm55, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (1901/720 * ff[0] - (2774/720 * ff[1]) + (2616/720 * ff[2]) - + (1274/720 * ff[3]) + (251/720 * ff[4])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((475/1440 * fp) + (1427/1440 * ff[0]) - (798/1440 * ff[1]) + + (482/1440 * ff[2]) - (173/1440 * ff[3]) + (27/1440 * ff[4])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 5, 2); + + Fb1_ODEintdef(\abm65, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (4277/1440 * ff[0] - (7923/1440 * ff[1]) + (9982/1440 * ff[2]) - + (7298/1440 * ff[3]) + (2877/1440 * ff[4]) - (475/1440 * ff[5])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((475/1440 * fp) + (1427/1440 * ff[0]) - (798/1440 * ff[1]) + + (482/1440 * ff[2]) - (173/1440 * ff[3]) + (27/1440 * ff[4])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 6, 2); + + Fb1_ODEintdef(\abm66, + { |odeDef, t, y, dt, size ... args| + var yy, ff, p, fp, yNew, fNew; + yy = y.collect(_[0..size-1]); + ff = y.collect(_[size..2*size-1]); + p = (4277/1440 * ff[0] - (7923/1440 * ff[1]) + (9982/1440 * ff[2]) - + (7298/1440 * ff[3]) + (2877/1440 * ff[4]) - (475/1440 * ff[5])) * dt + yy[0]; + fp = odeDef.(nil, t + dt, p, *args); + yNew = ((19087/60480 * fp) + (65112/60480 * ff[0]) - (46461/60480 * ff[1]) + + (37504/60480 * ff[2]) - (20211/60480 * ff[3]) + (6312/60480 * ff[4]) - + (863/60480 * ff[5])) * dt + yy[0]; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 6, 2); + + initKeys = all.keys; + } + + initFb1_ODEintdef { |name| + + (initKeys.notNil and: { initKeys.includes(name) }).if { + var err = SimpleInitError("Fb1_ODEintdef of this name already exists"); + err.class_("Fb1_ODEintdef"); + err.throw; + }; + + all.put(name, this) + } +} diff --git a/Classes/Nonlinear/GFIS.sc b/Classes/Nonlinear/GFIS.sc new file mode 100644 index 0000000..0a1cd52 --- /dev/null +++ b/Classes/Nonlinear/GFIS.sc @@ -0,0 +1,55 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +GFIS : UGen { + + *new { |outRate, func, init, n = 1, nOut, leakDC = true, leakCoef = 0.995| + var sigs, outSig; + nOut = nOut ?? { n }; + sigs = 0!n; + n.do { |i| + sigs[i] = (i == 0).if { + func.(init, 0) + }{ + func.(sigs[i-1], i) + } + }; + outSig = nOut.isKindOf(SequenceableCollection).if { + nOut.collect { |i| Select.perform(outRate, i-1, sigs) } + }{ + Select.perform(outRate, nOut-1, sigs) + }; + ^leakDC.if { LeakDC.perform(outRate, outSig, leakCoef) }{ outSig } + } + + *ar { |func, init, n = 1, nOut, leakDC = true, leakCoef = 0.995| + ^this.new(\ar, func, init, n, nOut, leakDC, leakCoef) + } + + *kr { |func, init, n = 1, nOut, leakDC = true, leakCoef = 0.995| + ^this.new(\kr, func, init, n, nOut, leakDC, leakCoef) + } +} + diff --git a/Classes/Nonlinear/extObject.sc b/Classes/Nonlinear/extObject.sc new file mode 100644 index 0000000..25b895d --- /dev/null +++ b/Classes/Nonlinear/extObject.sc @@ -0,0 +1,29 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Object { + miSC_isAr { ^false } +} + diff --git a/Classes/Nonlinear/extSequenceableCollection.sc b/Classes/Nonlinear/extSequenceableCollection.sc new file mode 100644 index 0000000..b2ba69d --- /dev/null +++ b/Classes/Nonlinear/extSequenceableCollection.sc @@ -0,0 +1,86 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++SequenceableCollection { + + miSC_adaptFb1ArgList { |in, countOffset| + // expects argList as receiver + var count = countOffset, adaptedFb1ArgList; + adaptedFb1ArgList = this.collect { |argItem, i| + argItem.isCollection.if { + argItem.collect { |y, j| + y.miSC_isAr.if { + count = count + 1; + in[count] + }{ + y + } + } + }{ + argItem.miSC_isAr.if { + count = count + 1; + in[count] + }{ + argItem + } + } + }; + // need count again in Fb1 + ^[adaptedFb1ArgList, count] + } + + +// method for applying functions on numeric approximations with Fb1_ODE + + miSC_fb1_perform { |thing, in, size, outSize| + var valueArray, addArray, composed; + ^thing.isNil.if { + this + }{ + valueArray = this[0..size-1]; + addArray = this[size..outSize-1]; + + composed = thing.isKindOf(SequenceableCollection).if { + // if an array is passed to compose, then + // a Function in it applies to the whole current y (which is an array) + // whereas an operator applies to the respective component + valueArray.collect { |x, i| + var thingI = thing.miSC_maybeWrapAt(i); + thingI.isKindOf(Function).if { + thingI.applyTo(valueArray, in) + }{ + thingI.applyTo(x, in) + } + } + }{ + thing.applyTo(valueArray, in) + }; + composed ++ addArray + } + } +} + + + diff --git a/Classes/Nonlinear/extUGen.sc b/Classes/Nonlinear/extUGen.sc new file mode 100644 index 0000000..d542e36 --- /dev/null +++ b/Classes/Nonlinear/extUGen.sc @@ -0,0 +1,28 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++UGen { + miSC_isAr { ^this.rate == 'audio' } +} diff --git a/Classes/Other/DIdev.sc b/Classes/Other/DIdev.sc new file mode 100644 index 0000000..602e9ac --- /dev/null +++ b/Classes/Other/DIdev.sc @@ -0,0 +1,125 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// this code now looks straight, but it was hard to figure out ... +// taking the correct stutterings is the trick + + +// weights accept array of drate ugens +// currently this handles the case which is needed for DIdev, +// but not an arbitrary input of possibly nested drate ugens, +// therefore only recommended for use in this context + +Dwrand_DIdev : DUGen { + *new { |list, weights, normalize = 0, repeats = 1| + var partialWeights, index = 0, sum = 1, dwhite; + + (normalize != 0).if { + sum = 0; + // weights have to be stuttered selectively as weights[list.size-1] won't be needed below + weights = weights.collect { |w, i| Dstutter((i + 1 < list.size).if { 2 }{ 1 }, w) }; + list.size.do { |i| sum = sum + Dswitch1(weights, i) }; + }; + + dwhite = Dstutter(list.size - 1, Dwhite(0, sum, repeats)); + + partialWeights = 0 ! (list.size - 1); + partialWeights[0] = Dstutter(list.size - 1, Dswitch1(weights, 0)); + (list.size - 2).do { |i| + partialWeights[i+1] = Dstutter(list.size - 2 - i, Dswitch1(weights, i+1)) + partialWeights[i]; + }; + + (list.size - 1).do { |i| index = index + (dwhite > partialWeights[i]) }; + + ^Dswitch1(list, index) + } +} + + + +// similar trigger tricks + +// triggering difs triggers (maxLookBack * src, maxLookBack * phase) +// triggering probs triggers (maxHiDev - maxLoDev + 1) * difs + +// triggering Dbufwr in addition triggers src and phase, so all in all we need +// maxLookBack * maxSpan + 1 as stutter number for src and phase +// whereas maxSpan = (maxHiDev - maxLoDev + 1) + + +DIdev : DUGen { + + *new { |in = 0, maxLookBack = 5, minLoDev = -5, maxHiDev = 5, lookBack, loDev, hiDev, thr = 1e-3, length = inf| + + var buf = LocalBuf(maxLookBack + 1).clear.set(inf!(maxLookBack + 1)), add, + phase, src, dif, difs, probs, wr, maxSpan = maxHiDev - minLoDev + 1, + indicatorLoDev = 1, indicatorHiDev = 1, sel; + + src = Dstutter(maxLookBack * maxSpan + 1, in); + phase = Dstutter(maxLookBack * maxSpan + 1, Dseries(0)); + + loDev.isKindOf(DUGen).if { loDev = Dstutter(maxSpan, loDev) }; + hiDev.isKindOf(DUGen).if { hiDev = Dstutter(maxSpan, hiDev) }; + lookBack.isKindOf(DUGen).if { lookBack = Dstutter(maxLookBack * maxSpan, lookBack) }; + + // buffer is rewritten cyclically, so look back like this + difs = { |i| Dbufrd(buf, phase - i - 1 % (maxLookBack + 1)) - src } ! maxLookBack; + + // for each index between bounds this indicates if there's an occurrence in the past, + // if yes then probs is set to 0 + + probs = { |i| + var ind = 0; + // consider dynamic lookBack here + maxLookBack.do { |j| ind = ind + (((difs[j] - minLoDev - i).abs < thr) * + (lookBack.isNil.if { + 1 + }{ + sel = UGen.miSC_methodSelectorForRate(lookBack.rate); + (sel == \ar).if { SimpleInputError("no audio rate input allowed as lookBack arg").throw }; + DC.perform(sel, j) < lookBack + })) + }; + 1 - ind.sign + } ! maxSpan; + + // generate indicator arrays if certain -- possibly dynamic -- deviations are given + loDev.notNil.if { + sel = UGen.miSC_methodSelectorForRate(loDev.rate); + indicatorLoDev = { |i| loDev <= DC.perform(sel, i + minLoDev) } ! maxSpan + }; + hiDev.notNil.if { + sel = UGen.miSC_methodSelectorForRate(hiDev.rate); + indicatorHiDev = { |i| DC.perform(sel, i + minLoDev) <= hiDev } ! maxSpan + }; + + probs = (probs * indicatorLoDev * indicatorHiDev); + + add = Dwrand_DIdev((minLoDev..maxHiDev), probs, 1, length); + + ^Dbufwr(src + add, buf, phase); + } +} + diff --git a/Classes/Other/extPlatform.sc b/Classes/Other/extPlatform.sc new file mode 100644 index 0000000..65d5d0b --- /dev/null +++ b/Classes/Other/extPlatform.sc @@ -0,0 +1,51 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++ Platform { + *miSCellaneousDirs { |withWarnings = true| + var dirs = (Platform.userExtensionDir +/+ "miSCellaneous*").pathMatch ++ + (Platform.systemExtensionDir +/+ "miSCellaneous*").pathMatch ++ + (Platform.userExtensionDir +/+ "miSCellaneous*" +/+ "miSCellaneous*").pathMatch ++ + (Platform.systemExtensionDir +/+ "miSCellaneous*" +/+ "miSCellaneous*").pathMatch ++ + (Platform.userAppSupportDir +/+ "quarks" +/+ "miSCellaneous*").pathMatch ++ + (Platform.systemAppSupportDir +/+ "quarks" +/+ "miSCellaneous*").pathMatch ++ + (Platform.userAppSupportDir +/+ "downloaded-quarks" +/+ "miSCellaneous*").pathMatch ++ + (Platform.systemAppSupportDir +/+ "downloaded-quarks" +/+ "miSCellaneous*").pathMatch; + dirs = dirs.select { |p| PathName(p).isFolder and: { PathName(p +/+ "Classes").isFolder } }; + withWarnings.if { + case + { dirs.size == 0 }{ + "\nWARNING: no directory beginning with name 'miSCellaneous' found within extension directories\n".postln; + } + { dirs.size > 1 }{ + ("\nWARNING: more than one directory beginning with name 'miSCellaneous' found within extension directories,\n" ++ + "there might be a discrepancy\n").postln; + } + { true }{ } + }; + ^dirs + } +} + diff --git a/Classes/Other/extUGen.sc b/Classes/Other/extUGen.sc new file mode 100644 index 0000000..ca10e40 --- /dev/null +++ b/Classes/Other/extUGen.sc @@ -0,0 +1,31 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++ UGen { + *miSC_methodSelectorForRate { |rate| + var sel = this.methodSelectorForRate(rate); + ^(sel == \new).if { \kr }{ sel } + } +} diff --git a/Classes/Patterns/AddEventTypes_PbindFx.sc b/Classes/Patterns/AddEventTypes_PbindFx.sc new file mode 100644 index 0000000..b592729 --- /dev/null +++ b/Classes/Patterns/AddEventTypes_PbindFx.sc @@ -0,0 +1,282 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +AddEventTypes_PbindFx { + + *initClass { + StartUp.add { + AddEventTypes_PbindFx.makeZeroSynthDef; + AddEventTypes_PbindFx.makeSplitZeroSynthDef; + AddEventTypes_PbindFx.makeSplitSynthDefs(8, 8); + }; + AddEventTypes_PbindFx.makeEventType_pbindFx; + } + + *makeEventType_pbindFx { + Event.addEventType(\pbindFx, + Event.default.eventTypes[\note] <> { |server| + // The array ~fxOrder contains the topological order of effect graph as indices, + // 0 (src) is not contained, the smallest effect index is 1. + // The dictionary ~fxPredecessors contains the fx graph's predecessors, + // also those of \o (out). + // The dictionary ~fxSuccessors contains the fx graph's successors, + // also those of 0 (src). + + var fxNum, // size of ~fxOrder + fxBuses, // array of fx input buses (contains nils if there is no in !), + // size = fxNum + splitBuses, // array of split synth input buses, + // contains nils for effects without split, + // size = fxNum, but different to fxBuses the first item refers to the source + // the last fx in topological order never needs a split + splitFactors, // array of split synths' split factors, 1 means no split, size = fxNum + fxOrderPositions, // dictionary of fx index position in ~fxOrder (+ 1, contains 0 too) + firstFxIds, lastFxIds, // these arrays (size = fxNum) keep track of zero synth ordering + // in fxGroup, needed as zero synths are established before fx synths, + // relevant is first and last zero synth per fx slot + + cleanupDelaySums, // array of cleanup delays after src and fxs, + // therefore contains fxNum + 1 items, + // this array is ordered in the case of an fx sequence but not for a general fx graph, + // thus we need a variable for this: + latestCleanupIndex, + withFxs, startFxBundle, startZeroBundle = [], cleanupClockTempo, + baseLatency, hasGate, gateDelay, cleanupDelta, skipjack, startTime, zeroSynthOverlap, + fxGroupId, srcGroupId, startSplitBundle, startSplitZeroBundle, splitSynthIds; + + ~cleanupDelay = ~cleanupDelay ?? { PbindFx.defaultSourceCleanupDelay }; + ~cleanupDt = ~cleanupDt ?? { PbindFx.defaultCleanupDt }; + ~cleanupClock = ~cleanupClock ?? { SystemClock }; + ~freePerGroup = ~freePerGroup ?? { false }; + + cleanupClockTempo = (~cleanupClock === SystemClock).if { 1 }{ ~cleanupClock.tempo }; + zeroSynthOverlap = server.options.blockSize / server.sampleRate; + + // unifying ~fxOrder order data (with topo order etc) has been defined in + // AbstractPbindFx / miSC_getFxOrderData + + ~fxOrder = ~fxOrder.asArray; + fxOrderPositions = IdentityDictionary(); + fxOrderPositions.put(0, 0); + ~fxOrder.do { |x,i| fxOrderPositions.put(x, i+1) }; + + fxNum = ~fxOrder.size; + withFxs = ((fxNum == 1) && (~fxOrder[0] == 0)).not; + + withFxs.if { + cleanupDelaySums = [~cleanupDelay]; + baseLatency = (~latency ?? { server.latency }); + + // fxGroup: group for all synths related to the event + // srcGroup: placed at top of fxGroup + // in general this node order wil be established (index shift from code): + + // fxGroup: + // srcGroup: + // (splitZero #1 writes 0 to splitbus, in case src will write to such) + // zero #1 writes 0 to bus(es), to which src (or split of src) will write + // src writes to whatever buses + // (split #1 in case src writes to more than one bus) + // (splitZero #2 writes 0 to splitbus, in case fx #1 will write to such) + // (zero #2 writes 0 to bus(es), to which fx #1 (or split of fx #1) will write) + // fx #1 reads from buses #1, writes to whatever buses + // (split #2 in case fx #1 writes to more than one bus) + + // ... + + // (splitZero #n writes 0 to splitbus, in case fx #n-1 will write to such) + // (zero #n writes 0 to bus(es), to which fx #n-1 (or split of fx #n-1) will write) + + // fx #n-1 reads from whatever, writes to whatever + // (split #n in case fx #n-1 writes to more than one bus) + // fx #n reads from whatever, writes to out + + fxGroupId = server.nextNodeID; + srcGroupId = server.nextNodeID; + server.sendBundle(nil, + [21, fxGroupId, ~addAction ?? { 0 }, ~group.value.asNodeID], + [21, srcGroupId, 0, fxGroupId] + ); + + // Per convention \cleanupDelay of src synth indicates: + // maximum release time in case of a gated envelope + // maximum synth duration in case of a fixed length envelope. + // gateDelay adds delay times depending on env type, + // it refers to beats and thus will be added to ~timingOffset. + + ~instrument = ~instrument.asSymbol; + hasGate = SynthDescLib.global[~instrument].controlNames.includes(\gate); + gateDelay = hasGate.if { ~sustain.value }{ 0 }; + + // reserve buses with right sizes, + // this looks at fx SynthDef's in sizes + + #fxBuses, splitBuses, splitFactors, cleanupDelaySums = ~fxOrder.miSC_getFxBusData( + ~fxPredecessors, ~fxSuccessors, fxOrderPositions, + ~fxEvents, ~instrument, ~otherBusArgs, ~cleanupDelay, server + ); + + latestCleanupIndex = cleanupDelaySums.maxIndex; + // avoid cleanup ambivalence with two latest cleanups + cleanupDelaySums[latestCleanupIndex] = cleanupDelaySums[latestCleanupIndex] + 0.01; + + // startFxBundle and startZerobundle are just collected and scheduled afterwards + // freeing with freeFxBundle and freeZeroBundle is either + // (1) scheduled at once by freeing fxGroup (with option ~freePerGroup == true) or + // (2) scheduled separately (with option ~freePerGroup == false) + // (1) and (2) is done within the methods + + #startZeroBundle, startSplitBundle, startSplitZeroBundle, firstFxIds, lastFxIds, splitSynthIds = + ~fxOrder.miSC_makeStartZeroBundle( + ~fxPredecessors, ~fxSuccessors, fxOrderPositions, fxBuses, splitBuses, splitFactors, + fxNum, srcGroupId, fxGroupId, baseLatency, cleanupDelaySums, latestCleanupIndex, + gateDelay, ~out, ~freePerGroup, ~timingOffset, ~lag, zeroSynthOverlap, server + ); + + startFxBundle = ~fxOrder.miSC_makeStartFxBundle(~fxSuccessors, + fxOrderPositions, fxBuses, splitBuses, splitFactors, ~fxEvents, srcGroupId, + fxGroupId, firstFxIds, lastFxIds, baseLatency, cleanupDelaySums, latestCleanupIndex, + gateDelay, ~out, ~freePerGroup, ~timingOffset, ~lag, server + ); + + // now start bundles that have been collected + // schedule zero synths, split synths and split zero synths slightly before fxs synths + schedBundleArrayOnClock( + ~timingOffset, thisThread.clock, startZeroBundle, ~lag, server, + baseLatency - zeroSynthOverlap + ); + + schedBundleArrayOnClock( + ~timingOffset, thisThread.clock, startSplitZeroBundle, ~lag, server, + baseLatency - (zeroSynthOverlap * 0.75) + ); + + schedBundleArrayOnClock( + ~timingOffset, thisThread.clock, startSplitBundle, ~lag, server, + baseLatency - (zeroSynthOverlap * 0.5) + ); + + // schedule fx synths + schedBundleArrayOnClock( + ~timingOffset, thisThread.clock, startFxBundle, ~lag, server, baseLatency + ); + + // free buses of fx chain after summed cleanup time + + cleanupDelta = baseLatency + cleanupDelaySums.last * cleanupClockTempo; + startTime = ~cleanupClock.seconds; + + skipjack = SkipJack( + dt: ~cleanupDt * cleanupClockTempo, + clock: ~cleanupClock + ); + skipjack.stopTest = { + (skipjack.clock.seconds - startTime > cleanupDelta).if { + fxBuses.do(_.free); + splitBuses.do(_.free); + // skipjacks stopped by stopTest are not automatically removed + skipjack.miSC_cleanup; + true + }{ + false + }; + }; + + // route source synth out into fx chain + + // source synth(s), which will refer to ~group and ~addAction, + // will be placed at tail of srcGroup or before split synth (also in srcGroup), + // so anyway before fx synths + + (splitFactors[0] > 1).if { + ~out = splitBuses[0].index; + ~group = [splitSynthIds[0]]; + ~addAction = \addBefore; + + }{ + // ~out = fxBuses[0].index; + ~out = fxBuses[fxOrderPositions[~fxSuccessors[0].first] - 1].index; + ~group = [srcGroupId]; + ~addAction = \addToTail; + }; + + }; + server; + } + ) + } + + *makeZeroSynthDef { + SynthDef(\pbindFx_zero, { |out| + ReplaceOut.ar(out, DC.ar(0)) + }, [\ir]).store; + } + + // like \pbindFx_zero, but makes order more clear when doing s.queryAllNodes while running + *makeSplitZeroSynthDef { + SynthDef(\pbindFx_splitZero, { |out| + ReplaceOut.ar(out, DC.ar(0)) + }, [\ir]).store; + } + + *makeSplitSynthDef { |splitNum, channelNum| + SynthDef("pbindFx_split_" ++ splitNum ++ "x" ++ channelNum, { |in| + var out = \out.kr(0!splitNum); + Out.ar(out, In.ar(in, channelNum)) + }, [\ir]).store; + } + + *makeSplitSynthDefs { |maxSplitNum, maxChannelNum| + for(2, maxSplitNum, { |i| + for(1, maxSplitNum, { |j| + this.makeSplitSynthDef(i,j) + }) + }); + } + +} + + ++SkipJack { + miSC_cleanup { + all.remove(this); + CmdPeriod.remove(this); + if( verbose ) { ("SkipJack" + name + "stopped.").postcln }; + } +} + + ++SequenceableCollection { + miSC_collectEvalWithoutKeyPairs { |syms, ev| + var coll; + this.pairsDo { |k,v| syms.includes(k).not.if { coll = coll.addAll([k, ev.use { v.() }]) } }; + ^coll + } +} + + + + + diff --git a/Classes/Patterns/EventShortcuts.sc b/Classes/Patterns/EventShortcuts.sc new file mode 100644 index 0000000..1de25b9 --- /dev/null +++ b/Classes/Patterns/EventShortcuts.sc @@ -0,0 +1,263 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +EventShortcuts { + classvar prefixFunc); + } + } + } + +} + + + + diff --git a/Classes/Patterns/MemoRoutine.sc b/Classes/Patterns/MemoRoutine.sc new file mode 100644 index 0000000..ea28bda --- /dev/null +++ b/Classes/Patterns/MemoRoutine.sc @@ -0,0 +1,78 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +MemoRoutine : Stream { + + var <>routine, <>lastValues, <>count, <>copyItems, <>copySets; + + *new { |func, stackSize = (512), bufSize = 1, copyItems = 0, copySets = 1| + ^super.new.routine_(Routine(func, stackSize)).lastValues_({}!bufSize).count_(0) + .copyItems_(copyItems.miSC_getCopyCode).copySets_(copySets.miSC_getCopyCode) + } + + next { |inval| + var newLastValues, val = routine.next(inval); + newLastValues = this.lastValues.shift(1, val.miSC_copy(copyItems, copySets)); + this.lastValues = newLastValues; + count = count + 1; + ^val + } + + value { |inval| + var newLastValues, val = routine.next(inval); + newLastValues = this.lastValues.shift(1, val.miSC_copy(copyItems, copySets)); + this.lastValues = newLastValues; + count = count + 1; + ^val + } + + resume { |inval| + var newLastValues, val = routine.next(inval); + newLastValues = this.lastValues.shift(1, val.miSC_copy(copyItems, copySets)); + this.lastValues = newLastValues; + count = count + 1; + ^val + } + + run { |inval| + var newLastValues, val = routine.next(inval); + newLastValues = this.lastValues.shift(1, val.miSC_copy(copyItems, copySets)); + this.lastValues = newLastValues; + count = count + 1; + ^val + } + + bufSize { ^lastValues.size } + + at { |i| ^lastValues[i] } + + lastValue { ^lastValues[0] } + + reset { routine.reset } + + stop { routine.stop } +} + + + diff --git a/Classes/Patterns/OtherPatterns.sc b/Classes/Patterns/OtherPatterns.sc new file mode 100755 index 0000000..daac51f --- /dev/null +++ b/Classes/Patterns/OtherPatterns.sc @@ -0,0 +1,275 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +Pshufn : ListPattern { + embedInStream { |inval| + var item, stream; + repeats.value(inval).do { |j| + (0..(list.size-1)).scramble.do { |i| + item = list.wrapAt(i); + inval = item.embedInStream(inval); + }; + }; + ^inval; + } +} + +PlaceAll : Ppatlace { + *new { |list, repeats = 1, offset = 0| + var laceList = list.miSC_makeLaceList; + ^super.new(laceList, repeats, offset); + + } +} + + +////////////////// + + +PmonoPar : Plazy { + *new { |setPatternPairs, defname = \default, offset = 1e-6| + ^super.new({ + var g = Group(), cleanup = EventStreamCleanup.new; + Pseq([ + Pbind( + \instrument, defname, + \type, Pseq([\on]), + \dur, offset, + \group, g, + \cleanup, Pfunc { |e| cleanup.addFunction(e, { g.release }) } + ), + Ptpar(setPatternPairs.collect { |p, j| + var pairs, keys = p.select { |x,i| i.even }, keysAfterDur; + keysAfterDur = keys.copyToEnd(keys.indexOf(\dur) + 1); + #[note, degree, midinote].any { |x| keysAfterDur.includes(x) }.if { + keysAfterDur = keysAfterDur.add(\freq) + }; + pairs = [\type, \set] ++ p ++ + keys.includes(\args).not.if { [\args, keysAfterDur] } ++ + [\id, g]; + [j * offset, Pbind(*pairs)] + }.flatten), + Pbind(\instrument, defname, \type, Pseq([\off]), \dur, offset, \group, g) + ]) + }) + } +} + +PpolyPar : Plazy { + *new { |setPatternPairs, defNames = #[default], order, offset = 1e-6| + ^super.new({ + var cleanup, size = defNames.size, groups, hasSynthsForAllStreams, hasNoSynthsForAnyStream; + + cleanup = EventStreamCleanup.new; + + order = order ?? { (0..size-1) }; + groups = nil ! size; + size.do { |i| groups[order[i]] = (i != 0).if { Group(groups[order[i-1]], \addAfter) }{ Group() } }; + + hasSynthsForAllStreams = setPatternPairs.every { |x| x.includes(\synths) }; + hasNoSynthsForAnyStream = setPatternPairs.every { |x| x.includes(\synths).not }; + + (hasSynthsForAllStreams.not && (hasNoSynthsForAnyStream && (size == setPatternPairs.size)).not).if { + SimpleInitError("\\synths must be either defined for all streams or the number of streams must " ++ + "equal the number of defNames.\n" ++ "In that case each setting stream refers to the " ++ + "synth at the same position of defNames." + ).throw + }; + + Pseq( + groups.collect { |g, i| + Pbind( + \instrument, defNames[i], + \type, Pseq([\on]), + \dur, offset, + \group, g, + \cleanup, Pfunc { |e| cleanup.addFunction(e, { g.release }) } + ) + } ++ + + Ptpar(setPatternPairs.collect { |p, j| + var pairs, keys = p.select { |x,i| i.even }, keysAfterDur; + keysAfterDur = keys.copyToEnd(keys.indexOf(\dur) + 1); + #[note, degree, midinote].any { |x| keysAfterDur.includes(x) }.if { + keysAfterDur = keysAfterDur.add(\freq) + }; + pairs = hasNoSynthsForAnyStream.if { [\synths, j] }{ [] } ++ + [\type, \set] ++ p ++ + keys.includes(\args).not.if { [\args, keysAfterDur] } ++ + [\id, Pfunc { |e| groups[e[\synths].asArray] } ]; + [j * offset, Pbind(*pairs)] + }.flatten) ++ + + groups.collect { |g, i| + Pbind(\instrument, defNames[i], \type, Pseq([\off]), \dur, offset, \id, g) + } + ) + }) + } +} + + +////////////////// + + +PSloop : Pattern { + var <>psPat, <>lookBack, <>doSkip, <>loopFunc, <>loopFuncPerItem, <>loopFuncAsGoFunc, <>goFunc, <>indices; + *new { |srcPat, length = inf, bufSize = 1, lookBack = 0, doSkip = 0, + loopFunc, loopFuncPerItem = 0, loopFuncAsGoFunc = 0, goFunc, indices, copyItems = 0, copySets = 1| + ^super.new.psPat_(PStream(srcPat, length, bufSize, copyItems, copySets)) + .lookBack_(lookBack).doSkip_(doSkip).loopFunc_(loopFunc) + .loopFuncPerItem_(loopFuncPerItem).loopFuncAsGoFunc_(loopFuncAsGoFunc) + .goFunc_(goFunc).indices_(indices); + } + embedInStream { |inval| + var psStream = psPat.asStream; + var lookBackStream, lastVals, lookBackVal, oldLookBackVal, lookBackValClipped, loopLength, + doSkipVal, count, mappedIndex, indicesStream, rawVal, mappedVal, + currentIndices, currentIndexOrder, getCurrentIndexOrder, loopFuncStream, currentLoopFunc, + loopFuncPerItemVal, goFuncStream, currentGoFunc, loopFuncAsGoFuncVal; + + getCurrentIndexOrder = { |nextIndices, indexbase| + nextIndices.isKindOf(Function).if { nextIndices.(indexbase) }{ nextIndices } + }; + + lookBackStream = case + { lookBack.isKindOf(Function) }{ Pfunc(lookBack) } + { lookBack.isKindOf(Pattern) }{ lookBack }.asStream; + + indicesStream = case + { indices.isKindOf(Function) || indices.isKindOf(SequenceableCollection) }{ Pn(indices) } + { indices.isKindOf(Pattern) }{ indices }.asStream; + + loopFuncStream = case + { loopFunc.isKindOf(Function) }{ Pn(loopFunc) } + { loopFunc.isKindOf(Pattern) }{ loopFunc }.asStream; + + goFuncStream = case + { goFunc.isKindOf(Function) }{ Pn(goFunc) } + { goFunc.isKindOf(Pattern) }{ goFunc }.asStream; + + lookBackVal = lookBackStream.next; + + while { + psPat.memoRoutine.notNil.if { lastVals = psPat.lastValues }; + lookBackVal.notNil + }{ + (lookBackVal > 0).if { + count = 0; + lookBackValClipped = min(lookBackVal, psPat.bufSize - 1); + currentIndices = indicesStream.next; + currentIndexOrder = getCurrentIndexOrder.(currentIndices, lookBackValClipped); + currentLoopFunc = loopFuncStream.next; + + while { lookBackVal > 0 }{ + lookBackValClipped = min(lookBackVal, psPat.bufSize - 1); + currentIndices.notNil.if { + mappedIndex = currentIndexOrder[count].clip(0, lookBackValClipped - 1); + loopLength = currentIndexOrder.size; + }{ + mappedIndex = count.mod(lookBackValClipped); + loopLength = lookBackValClipped; + }; + // index has to be reversed as PS buffers last at first + rawVal = lastVals.at(lookBackValClipped - 1 - mappedIndex); + mappedVal = currentLoopFunc.notNil.if { currentLoopFunc.(rawVal) }{ rawVal }; + + inval = mappedVal.embedInStream(inval); + count = count + 1; + loopFuncPerItemVal = loopFuncPerItem.(); + (loopFuncPerItemVal.miSC_check || (count >= loopLength)).if { + currentLoopFunc = loopFuncStream.next + }; + doSkipVal = doSkip.(); + (doSkipVal.miSC_check || (count >= loopLength)).if { + oldLookBackVal = lookBackValClipped; + lookBackVal = lookBackStream.next; + lookBackValClipped = min(lookBackVal, psPat.bufSize - 1); + ((oldLookBackVal != lookBackValClipped) || (count >= loopLength)).if { + count = 0; + (lookBackVal != 0).if { + currentIndices = indicesStream.next; + currentIndexOrder = getCurrentIndexOrder.(currentIndices, lookBackValClipped); + } + } + } + } + }{ + loopFuncAsGoFuncVal = loopFuncAsGoFunc.(); + currentGoFunc = loopFuncAsGoFuncVal.miSC_check.if { loopFuncStream }{ goFuncStream }.next; + + rawVal = psStream.next(inval); + mappedVal = currentGoFunc.notNil.if { currentGoFunc.(rawVal) }{ rawVal }; + + inval = mappedVal.embedInStream(inval); + lookBackVal = lookBackStream.next; + } + }; + ^inval; + } +} + + +////////////////// + + + +// This adapts an idea of James Harkins' PnNilSafe (ddwPatterns quark) for Psym, +// If all patterns in the Dictinonary return nil Psym's embedInStream +// can produce an infinite loop. +// It doesn't yield, so wrapping Psym into a PnNilSafe doesn't help in that case. +// Instead a check with logical time can be built into Psym itself. + +PsymNilSafe : Psym { + + var <>maxNull; + + *new { arg pattern, dict, maxNull = 128; + ^super.new(pattern).dict_(dict ?? { currentEnvironment }).maxNull_(maxNull) + } + + embedInStream { |inval| + var str, outval, pat, counter = 0, saveLogicalTime; + str = pattern.asStream; + while { + outval = str.next(inval); + outval.notNil + } { + pat = this.getPattern(outval); + saveLogicalTime = thisThread.clock.beats; + inval = pat.embedInStream(inval); + + if(thisThread.clock.beats == saveLogicalTime) { + counter = counter + 1; + if(counter > maxNull) { ^inval }; + } { + counter = 0; + }; + + }; + ^inval + } +} + diff --git a/Classes/Patterns/PIdev.sc b/Classes/Patterns/PIdev.sc new file mode 100644 index 0000000..21ead38 --- /dev/null +++ b/Classes/Patterns/PIdev.sc @@ -0,0 +1,92 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PIdev : Pattern { + + var <>pattern, <>maxLookBack = 3, <>loDev = -3, <>hiDev = 3, + <>lookBack, <>thr = 1e-3, <>length = inf; + + *new { |pattern, maxLookBack = 3, loDev = -3, hiDev = 3, + lookBack, thr = 1e-3, length = inf| + ^super.newCopyArgs(pattern, maxLookBack, loDev, hiDev, + lookBack, thr, length) + } + + embedInStream { arg inval; + var outval, srcVal, lookBackVal, loDevVal, hiDevVal, thrVal, count = 0, + difs, devs, probs, add; + var buf = inf ! (maxLookBack + 1); + var srcStr = pattern.asStream; + var lookBackStr = lookBack.asStream; + var loDevStr = loDev.asStream; + var hiDevStr = hiDev.asStream; + var thrStr = thr.asStream; + + length.value(inval).do { + srcVal = srcStr.next(inval); + if(srcVal.isNil) { ^inval }; + + lookBackVal = lookBackStr.next(inval) ?? { maxLookBack }; + loDevVal = loDevStr.next(inval); + hiDevVal = hiDevStr.next(inval); + thrVal = thrStr.next(inval); + + // this looks a bit different than in DIdev + + devs = (loDevVal.ceil..hiDevVal.floor); + + probs = devs.collect { |dev| + var j = 0, prob = 1, dif; + while { j < lookBackVal }{ + dif = buf[count - j - 1 % (maxLookBack + 1)] - srcVal - dev; + (dif.abs <= thrVal).if { j = lookBackVal; prob = 0 }; + j = j + 1 + }; + prob + }; + + add = devs.wchoose(probs.normalizeSum); + + outval = srcVal + add; + buf[count % (maxLookBack + 1)] = outval; + + count = count + 1; + inval = outval.yield; + }; + ^inval; + } + + storeArgs { ^[pattern, maxLookBack, loDev, hiDev, lookBack, thr, length] } +} + + +PLIdev : PIdev { + var <>envir; + *new { |pattern, maxLookBack = 3, loDev = -3, hiDev = 3, lookBack, thr = 1e-3, length = inf, envir = \current| + ^super.new(PL(pattern, 1, inf, envir), maxLookBack, PL(loDev, 1, inf, envir), PL(hiDev, 1, inf, envir), + PL(lookBack, 1, inf, envir), PL(thr, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[pattern, maxLookBack, loDev, hiDev, lookBack, thr, length, envir] } +} diff --git a/Classes/Patterns/PL.sc b/Classes/Patterns/PL.sc new file mode 100755 index 0000000..2bb0f8c --- /dev/null +++ b/Classes/Patterns/PL.sc @@ -0,0 +1,757 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PL_Pattern : Pattern { + var <>envir; + *new { |envir = \current| ^super.new.envir_(envir) } + + storeArgs { ^[envir] } + + data { ^this.envir.miSC_getEnvir[this.item] } +} + +PL_ListPattern : PL_Pattern { + var <>list, <>repeats = inf, <>cutItems; + *new { |list, repeats = inf, cutItems = true, envir = \current| + ^super.newCopyArgs(envir, list, repeats, cutItems) + } + storeArgs { ^[list, repeats, cutItems, envir] } +} + + +// "stream-save" Pn + +PL_Pn : PL_Pattern { + var <>item, <>repeats; + *new { |item, repeats = inf, envir = \current| + ^super.newCopyArgs(envir, item, repeats) + } + embedInStream { |inval| + var next; + item.isKindOf(Stream).if { + repeats.value(inval).do { + while { + next = item.next(inval); + next.notNil; + }{ + inval = next.yield; + }; + item.reset + }; + }{ + repeats.value(inval).do { inval = item.embedInStream(inval) } + }; + ^inval; + } + + storeArgs { ^[item, repeats, envir] } +} + + + +// PL_PproxyNth: Pattern for embedding the nth element of a PL_ListPattern + +// If nth element is updated just at the time a pattern or item at that position is being embedded, +// then it is replaced ad hoc if flag cutItems equals 1 or true, otherwise it might be embedded at next occasion. + + +PL_PproxyNth : PL_Pattern { + var <>listProxy, <>index, <>type, <>doWrap, <>cutItems; + *new { |listProxy, index, type = 1, doWrap = true, cutItems = true, envir = \current| + // type: repeats factor for objects other than Patterns and Streams to be embedded + ^super.newCopyArgs(envir, listProxy, index, type, doWrap, cutItems) + } + + nonListError { |src| + Error("PL_ListPattern requires list or reference to a " ++ + "non-empty collection; received " ++ src.asString ++ ".").throw; + } + + embedInStream { |inval| + var stream, next, src, rep, count = 0; + + listProxy.listHasChanged.not.if { + src = listProxy.source(index, doWrap); + rep = src.miSC_repTypeFactor(type); + stream = PL_Pn(src, rep, envir).asStream; + while { + listProxy.update(index); + // must check next value as we don't want replacement if stream is at end + next = listProxy.listHasChanged.not.if { + stream.next(inval) + }; + // possible replacement of nth item: + // third condition with count is necessary as otherwise a former replacement + // wouldn't be detected with cutItems == false + (listProxy.itemHasChanged && next.notNil && (cutItems.miSC_check || (count == 0))).if { + src = listProxy.source(index, doWrap); + rep = src.miSC_repTypeFactor(type); + stream = PL_Pn(src, rep, envir).asStream; + next = listProxy.listHasChanged.not.if { stream.next(inval) }; + }; + + next.isNil.if { listProxy.itemHasChanged = false; false }{ true }; + }{ + count = count + 1; + inval = next.yield; + }; + }; + ^inval + } + + storeArgs { ^[listProxy, index, type, doWrap, cutItems, envir] } +} + + + +PL_Pproxy : PL_Pattern { + var <>itemProxy, <>type, <>repeats; + *new { |itemProxy, type = inf, repeats = 1, envir = \current| + // type = 1 or inf, defines how to embed + // items other than Patterns or Streams + ^super.newCopyArgs(envir, itemProxy, type, repeats) + } + embedInStream { |inval| + var stream, next, src, repTypeFactor; + src = itemProxy.source; + repTypeFactor = src.miSC_repTypeFactor(type); + stream = PL_Pn(src, repTypeFactor * repeats, envir).asStream; + while { + itemProxy.update; + itemProxy.itemHasChanged.if { + src = itemProxy.source; + repTypeFactor = src.miSC_repTypeFactor(type); + stream = PL_Pn(src, repTypeFactor * repeats, envir).asStream; + itemProxy.itemHasChanged = false; + }; + next = stream.next(inval); + next.isNil.if { ^inval }{ true }; + }{ + inval = next.yield; + }; + ^inval + } + + storeArgs { ^[itemProxy, type, repeats, envir] } +} + + +// PL_ includes option for embed type +// type = 1 or inf, defines how to embed +// items other than Patterns or Streams + +PL : PL_Pattern { + var <>item, <>repeats, <>type; + *new { |item, repeats = inf, type = 1, envir = \current| + ^super.newCopyArgs(envir, item, repeats, type) + } + + embedInStream { |inval| + var itemProxy, repeatsProxy, stream, next; + itemProxy = PL_Proxy(item, envir); + repeatsProxy = PL_Proxy(repeats, envir); + stream = PL_Pproxy(itemProxy, type, repeatsProxy.source.value(inval), envir).asStream; + while { + next = stream.next(inval); + next.isNil.if { ^inval }{ true }; + }{ + inval = next.yield; + }; + ^inval + } + + storeArgs { ^[item, repeats, type, envir] } +} + + +// The following implementations are based on the corresponding classes in the main library +// Thanks to all authors, especially J.Harkins + + +PLseq : PL_ListPattern { + var <>offset; + *new { |list, repeats = inf, offset = 0, cutItems = true, envir = \current| + ^super.new(list, repeats, cutItems, envir).offset_(offset); + } + embedInStream { |inval| + var item, listProxy, offsetProxy, repeatsProxy, cutItemsProxy, ref = `true; + listProxy = PL_ListProxy(list, envir).update; + // avoid an infinite loop case + listProxy.streamSources.isNil.if { ^inval }; + + offsetProxy = PL_Proxy(offset, envir); + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + (inval.eventAt('reverse') == true).if { + repeatsProxy.source.value(inval).do { |j| + listProxy.reverseDo ({ |x,i| + inval = PL_PproxyNth(listProxy, i + offsetProxy.value, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged.if { + ref.value = false; + listProxy.listHasChanged = false; + }; + }, ref.value = true); + }; + }{ + repeatsProxy.source.value(inval).do { |j| + listProxy.do ({ |x, i| + item = PL_PproxyNth(listProxy, i + offsetProxy.value, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + inval = item; + listProxy.listHasChanged.if { + ref.value = false; + listProxy.listHasChanged = false; + }; + }, ref.value = true); + }; + }; + ^inval; + } + storeArgs { ^[list, repeats, offset, cutItems, envir] } +} + + + +PLser : PLseq { + + embedInStream { |inval| + var item, listProxy, offsetProxy, repeatsProxy, cutItemsProxy, j = 0; + + listProxy = PL_ListProxy(list, envir).update; + offsetProxy = PL_Proxy(offset, envir); + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + (inval.eventAt('reverse') == true).if { + listProxy.reverseDoN ({ |x,i| + inval = PL_PproxyNth(listProxy, i - j + offsetProxy.value, + cutItems: cutItemsProxy.value, envir: envir) + .embedInStream(inval); + listProxy.listHasChanged.if { + listProxy.listHasChanged = false; + j = i; + }; + }, repeatsProxy.source.value(inval)); + }{ + listProxy.doN ({ |x,i| + inval = PL_PproxyNth(listProxy, i - j + offsetProxy.value, + cutItems: cutItemsProxy.value, envir: envir) + .embedInStream(inval); + listProxy.listHasChanged.if { + listProxy.listHasChanged = false; + j = i; + }; + }, repeatsProxy.source.value(inval)); + }; + ^inval; + } +} + + +PLshuf : PL_ListPattern { + *new { |list, repeats = inf, cutItems = true, envir = \current| + ^super.new(list, repeats, cutItems, envir) + } + embedInStream { |inval| + var item, stream, order, listProxy, repeatsProxy, cutItemsProxy; + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + order = (0..(listProxy.listSource.size-1)).scramble; + + repeatsProxy.source.value(inval).do { |j| + listProxy.listHasChanged.if { + order = (0..(listProxy.listSource.size-1)).scramble; + listProxy.listHasChanged = false; + }; + order.do { |i| + inval = PL_PproxyNth(listProxy, i, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + }; + }; + ^inval; + } + + storeArgs { ^[list, repeats, cutItems, envir] } +} + + +PLshufn : PLshuf { + + embedInStream { |inval| + var item, stream, order, listProxy, repeatsProxy, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + repeatsProxy.source.value(inval).do { |j| + order = (0..(listProxy.listSource.size-1)).scramble; + order.do { |i| + inval = PL_PproxyNth(listProxy, i, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged = false; + }; + }; + ^inval; + } +} + +PLrand : PL_ListPattern { + *new { |list, repeats = inf, cutItems = true, envir = \current| + ^super.new(list, repeats, cutItems, envir) + } + + embedInStream { |inval| + var index, listProxy, repeatsProxy, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + repeatsProxy.source.value(inval).do { |i| + index = listProxy.size.rand; + inval = PL_PproxyNth(listProxy, index, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged = false; + }; + ^inval; + } +} + + +PLxrand : PL_ListPattern { + *new { |list, repeats = inf, cutItems = true, envir = \current| + ^super.new(list, repeats, cutItems, envir) + } + + embedInStream { |inval| + var item, size, index, listProxy, repeatsProxy, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + index = listProxy.size.rand; + repeatsProxy.source.value(inval).do { |i| + size = listProxy.size; + index = (index + (size - 1).rand + 1) % size; + inval = PL_PproxyNth(listProxy, index, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged = false; + }; + ^inval; + } +} + + +PLwrand : PL_ListPattern { + var <>weights; + *new { |list, weights, repeats = inf, cutItems = true, envir = \current| + ^super.new(list, repeats, cutItems, envir).weights_(weights) + } + + embedInStream { |inval| + var item, weightsStream, nextWeight, listProxy, weightsProxy, repeatsProxy, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + weightsProxy = PL_Proxy(weights, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + weightsStream = PL_Pproxy(weightsProxy, envir: envir).asStream; + + repeatsProxy.source.value(inval).do { |i| + nextWeight = weightsStream.next; + nextWeight.isNil.if { ^inval }; + inval = PL_PproxyNth(listProxy, nextWeight.windex, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged = false; + }; + ^inval + } + + storeArgs { ^[list, weights, repeats, cutItems, envir] } +} + +PLswitch : PL_Pattern { + var <>list, <>which = 0, <>cutItems; + *new { |list, which = 0, cutItems = true, envir = \current| + ^super.newCopyArgs(envir, list, which, cutItems) + } + embedInStream { |inval| + var item, index, listProxy, indexProxy, indexStream, cutItemsProxy; + listProxy = PL_ListProxy(list, envir).update; + indexProxy = PL_Proxy(which, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + indexStream = PL_Pproxy(indexProxy, envir: envir).asStream; + + while { + (index = indexStream.next(inval)).notNil; + }{ + inval = PL_PproxyNth(listProxy, index, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged = false; + }; + ^inval; + } + storeArgs { ^[list, which, cutItems, envir] } +} + + +PLswitch1 : PLswitch { + + embedInStream { |inval| + var index, outval, indexProxy, listProxy, streamList, indexStream, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + indexProxy = PL_Proxy(which, envir); + indexStream = PL_Pproxy(indexProxy, envir: envir).asStream; + cutItemsProxy = PL_Proxy(cutItems, envir); + + streamList = listProxy.size.collect { |i| + PL_PproxyNth(listProxy, i, inf, cutItems: cutItems, envir: envir).asStream + }; + + loop { + listProxy.update.listHasChanged.if { + streamList = listProxy.size.collect { |i| + PL_PproxyNth(listProxy, i, inf, + cutItems: cutItemsProxy.value, envir: envir).asStream + }; + listProxy.listHasChanged = false; + }; + (index = indexStream.next).isNil.if { ^inval }; + outval = streamList[index].next(inval); + outval.isNil.if { ^inval }; + inval = outval.yield; + }; + } +} + + +PLtuple : PL_ListPattern { + + embedInStream { |inval| + var item, streamList, tuple, outval, listProxy, repeatsProxy, cutItemsProxy; + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + repeatsProxy.source.value(inval).do { |j| + var sawNil = false; + streamList = listProxy.size.collect { |i| + PL_PproxyNth(listProxy, i, inf, + cutItems: cutItemsProxy.value, envir: envir).asStream + }; + + while { + listProxy.update.listHasChanged.if { + streamList = listProxy.size.collect { |i| + PL_PproxyNth(listProxy, i, inf, + cutItems: cutItemsProxy.value, envir: envir).asStream + }; + listProxy.listHasChanged = false; + }; + tuple = Array.new(streamList.size); + streamList.do { |stream, j| + outval = stream.next(inval); + outval.isNil.if { sawNil = true; }; + tuple.add(outval); + }; + sawNil.not + }{ + inval = yield(tuple); + }; + }; + ^inval; + } +} + + +PLslide : PL_ListPattern { + var <>len, <>step, <>start, <>wrapAtEnd; + *new { |list, repeats = inf, len = 3, step = 1, start = 0, wrapAtEnd = true, + cutItems = true, envir = \current| + ^super.new(list, repeats).len_(len).step_(step) + .start_(start).wrapAtEnd_(wrapAtEnd).cutItems_(cutItems).envir_(envir); + } + embedInStream { |inval| + var item, pos, stepStream, stepVal, lengthStream, lengthVal, next, stream, + listProxy, repeatsProxy, lengthProxy, stepProxy, + startProxy, wrapAtEndProxy, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + repeatsProxy = PL_Proxy(repeats, envir); + lengthProxy = PL_Proxy(len, envir); + stepProxy = PL_Proxy(step, envir); + startProxy = PL_Proxy(start, envir); + wrapAtEndProxy = PL_Proxy(wrapAtEnd, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + stepStream = PL_Pproxy(stepProxy, envir: envir).asStream; + lengthStream = PL_Pproxy(lengthProxy, envir: envir).asStream; + pos = startProxy.source.value; + + repeatsProxy.source.value(inval).do { + lengthVal = lengthStream.next(inval); + lengthVal.isNil.if { ^inval }; + wrapAtEndProxy.source.value.if { + lengthVal.do { |j| + item = PL_PproxyNth(listProxy, pos + j, + cutItems: cutItemsProxy.value, envir: envir); + inval = item.embedInStream(inval); + listProxy.listHasChanged = false; + } + }{ + lengthVal.do { |j| + listProxy.source(pos + j, false).isNil; + stream = PL_PproxyNth(listProxy, pos + j, doWrap: false, + cutItems: cutItemsProxy.value, envir: envir).asStream; + while { + next = stream.next; + listProxy.source(pos + j, false).isNil.if { ^inval }; + next.notNil + }{ + inval = next.embedInStream(inval); + } + }; + }; + stepVal = stepStream.next(inval); + stepVal.isNil.if { ^inval }; + pos = pos + stepVal; + }; + ^inval; + } + + storeArgs { ^[list, repeats, len, step, start, wrapAtEnd, cutItems, envir] } +} + + +PLwalk : PL_ListPattern { + + var <>start, <>step, <>direction; + *new { |list, step, direction = 1, start = 0, cutItems = true, envir = \current| + ^super.new(list).start_(start) + .step_(step ?? { Prand([-1, 1], inf) }) + .direction_(direction).cutItems_(cutItems).envir_(envir); + } + + embedInStream { |inval| + var step, index, stepStream, directionStream, direction, + listProxy, stepProxy, directionProxy, startProxy, cutItemsProxy; + + listProxy = PL_ListProxy(list, envir).update; + stepProxy = PL_Proxy(this.step, envir); + directionProxy = PL_Proxy(this.direction, envir); + startProxy = PL_Proxy(start, envir); + cutItemsProxy = PL_Proxy(cutItems, envir); + + stepStream = PL_Pproxy(stepProxy, envir: envir).asStream; + directionStream = PL_Pproxy(directionProxy, envir: envir).asStream; + + index = startProxy.source.value; + direction = directionStream.next(inval) ? 1; + + while { + step = stepStream.next(inval); + step.notNil + }{ + inval = PL_PproxyNth(listProxy, index, + cutItems: cutItemsProxy.value, envir: envir).embedInStream(inval); + listProxy.listHasChanged = false; + + step = step * direction; + (((index + step) < 0) or: { (index + step) >= listProxy.size }).if { + direction = directionStream.next(inval) ? 1; + step = step.abs * direction.sign; + }; + index = (index + step) % listProxy.size; + }; + ^inval; + } + + storeArgs { ^[list, step, direction, start, cutItems, envir] } +} + +////////////////////// + +PLwhite : Pwhite { + var <>envir; + *new { |lo = 0.0, hi = 1.0, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, length, envir] } +} + + +PLlprand : Plprand { + var <>envir; + *new { |lo = 0.0, hi = 1.0, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, length, envir] } +} + + +PLhprand : Phprand { + var <>envir; + *new { |lo = 0.0, hi = 1.0, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, length, envir] } +} + +PLmeanrand : Pmeanrand { + var <>envir; + *new { |lo = 0.0, hi = 1.0, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, length, envir] } +} + + +PLbrown : Pbrown { + var <>envir; + *new { |lo = 0.0, hi = 1.0, step = 0.125, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(step, 1, inf, envir), + PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, step, length, envir] } +} + + +PLgbrown : Pgbrown { + var <>envir; + *new { |lo = 0.0, hi = 1.0, step = 0.125, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(step, 1, inf, envir), + PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, step, length, envir] } +} + +////////////////////// + +PLseries : Pseries { + var <>envir; + *new { |start = 0, step = 1, length = inf, envir = \current| + ^super.new(PL(start, 1, inf, envir).asStream, PL(step, 1, inf, envir), + PL(length, length, inf, envir).asStream).envir_(envir) + } + storeArgs { ^[start, step, length, envir] } +} + + +PLgeom : Pgeom { + var <>envir; + *new { |start = 0, grow = 1, length = inf, envir = \current| + ^super.new(PL(start, 1, inf, envir).asStream, PL(grow, 1, inf, envir), + PL(length, length, inf, envir).asStream).envir_(envir) + } + storeArgs { ^[start, grow, length, envir] } +} + +////////////////////// + + +PLbeta : Pbeta { + var <>envir; + *new { |lo = 0.0, hi = 1.0, prob1 = 1, prob2 = 1, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(prob1, 1, inf, envir), + PL(prob2, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, prob1, prob2, length, envir] } +} + +PLcauchy : Pcauchy { + var <>envir; + *new { |mean = 0.0, spread = 1.0, length = inf, envir = \current| + ^super.new(PL(mean, 1, inf, envir), PL(spread, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[mean, spread, length, envir] } +} + +PLgauss : Pgauss { + var <>envir; + *new { |mean = 0.0, dev = 1, length = inf, envir = \current| + ^super.new(PL(mean, 1, inf, envir), PL(dev, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[mean, dev, length, envir] } +} + + +PLpoisson : Ppoisson { + var <>envir; + *new { |mean = 1, length = inf, envir = \current| + ^super.new(PL(mean, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[mean, length, envir] } +} + +PLexprand : Pexprand { + var <>envir; + *new { |lo = 0.0001, hi = 1.0, length = inf, envir = \current| + ^super.new(PL(lo, 1, inf, envir), PL(hi, 1, inf, envir), PL(length, length, 1, envir)).envir_(envir) + } + storeArgs { ^[lo, hi, length, envir] } +} + +////////////////////// + +PLnaryop : Pnaryop { + var <>envir; + *new { |operator, pat, arglist, envir = \current| + ^super.new(operator, PL(pat, 1, inf, envir), arglist.collect(PL(_, 1, inf, envir)) ).envir_(envir) + } +} + +PLnaryFunc : Pnaryop { + var <>envir; + *new { |func, pat, arglist, envir = \current| + ^super.new(\miSC_applyNaryFuncProxy, + PL(pat, 1, inf, envir), [PL(func, 1, inf, envir)] ++ arglist.collect(PL(_, 1, inf, envir)) ).envir_(envir) + } +} + + +////////////////////// + +PLn : Pn { + var <>item, <>repeats, <>envir; + *new { |item, repeats = inf, envir = \current| + ^super.newCopyArgs( + Plazy({ envir.miSC_getEnvir[item] }), + PL(repeats, repeats, 1, envir) + ) + } + storeArgs { ^[item, repeats, envir] } +} + + + diff --git a/Classes/Patterns/PL_ListProxy.sc b/Classes/Patterns/PL_ListProxy.sc new file mode 100644 index 0000000..e3abc99 --- /dev/null +++ b/Classes/Patterns/PL_ListProxy.sc @@ -0,0 +1,176 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +PL_ListProxy { + var <>symbol, <>listSource, <>streamSources, <>index, + <>itemHasChanged, <>listHasChanged, <>wrongList, <>envir; + + *new { |thing, envir = \current| + ^(thing.isKindOf(Symbol)).if { + super.new.symbol_(thing).envir_(envir.miSC_getEnvir) + }{ + thing.isKindOf(SequenceableCollection).not.if { + SimpleInputError("List input of PL_ListPattern must be SequenceableCollection.").throw; + }{ + super.new.listSource_(thing).streamSources_(thing) + } + }; + } + + + get { ^(symbol.isNil).if { listSource }{ envir[symbol] } } + + update { |i| + var currentList, j, k; + symbol.notNil.if { + currentList = this.get; + currentList.isKindOf(SequenceableCollection).not.if { + (currentList !== wrongList).if { + ("Embedding of PL_ListPattern encountered reference ('" ++ + symbol.asString ++ "') to an item not kind of a SequenceableCollection, " ++ + "reference ignored.").warn; + wrongList = currentList + } + }{ + (currentList !== listSource).if { + listHasChanged = index.notNil; + listSource = currentList; + streamSources = listSource.copy; + }{ + i.isNil.not.if { + j = i % currentList.size; + k = i % streamSources.size; + (currentList[j] !== streamSources[k]).if { + itemHasChanged = true; + streamSources[k] = currentList[j]; + }{ + itemHasChanged = false; + } + } + }; + } + }{ + index.isNil.if { listHasChanged = false; itemHasChanged = false } + }; + index = i; + ^this; + } + + do { |function, ref = (`true)| + var i = 0, size = this.streamSources.size; + while { + (i < size) and: { ref.() } + } { + function.value(this.source(i), i); + i = i + 1; + } + } + + doN { |function, n, ref = (`true)| + var i = 0; + while { + (i < n) and: { ref.() } + } { + function.value(this.source(i), i); + i = i + 1; + } + } + + reverseDo { |function, ref = (`true)| + var size = this.streamSources.size, i, j = 0; + i = size - 1; + while { + (i >= 0) and: { ref.() } + } { + function.value(this.source(i), j); + i = i - 1; + j = j + 1; + } + } + + reverseDoN { |function, n, ref = (`true)| + var size = this.streamSources.size, i, j = 0; + i = size - 1; + while { + (j < n) and: { ref.() } + } { + function.value(this.source(i), j); + i = i - 1; + j = j + 1; + } + } + + + size { ^this.listSource.size } + + value { |i| ^streamSources.wrapAt(i).value } + + source { |i, doWrap = true| + (streamSources.size > 0).if { + ^streamSources.perform(doWrap.if { \wrapAt }{ \at }, i) + }{ + Error("PL_ListPattern requires list or reference to a " ++ + "non-empty collection; received " ++ streamSources ++ ".").throw; + } + } + +} + + +PL_Proxy { + var <>symbol, <>streamSource, <>itemHasChanged, <>envir; + + *new { |thing, envir = \current, exclude = #[]| + ^((thing.isKindOf(Symbol)) && (exclude.includes(thing).not)).if { + super.new.symbol_(thing).envir_(envir.miSC_getEnvir) + }{ + super.new.streamSource_(thing) + } + } + + get { ^(symbol.isNil).if { streamSource }{ envir[symbol] } } + + update { + var currentItem; + symbol.notNil.if { + currentItem = this.get; + itemHasChanged = (currentItem !== streamSource).if { + streamSource = currentItem; + true; + }{ + false + }; + }{ + itemHasChanged = false; + }; + ^this + } + + value { this.update; ^streamSource.value } + + source { this.update; ^streamSource } +} + + + diff --git a/Classes/Patterns/PLbindef.sc b/Classes/Patterns/PLbindef.sc new file mode 100755 index 0000000..2cf5d58 --- /dev/null +++ b/Classes/Patterns/PLbindef.sc @@ -0,0 +1,132 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// Instances of this class are constructed implicitely and used for updating the PLbindef + +PLbindefEnvironment : Environment { + + var plbindefParEnvironment, <>plbindefArray; + + *new { |n = 8, proto, parent, know = true| + ^super.new(n).proto_(proto).parent_(parent).know_(know) + } + + put { |key, obj| + plbindefArray.do { |i, j| + plbindefParEnvironment[i].put(key, obj.miSC_maybeWrapAt(j)) + } + } + + at { |key| + ^(key.asString.last == $_).if { + // for subarray prototype setting we need normal 'at' + this.superPerform(\at, key) + }{ + // for subarray prototype getting we pull from PLbindefParEnvironments + plbindefArray.collect { |i| plbindefParEnvironment[i][key] } + } + } + + play { |clock, protoEvent, quant, doReset = false| + plbindefArray.do { |i, j| + plbindefParEnvironment[i].play( + clock.miSC_maybeWrapAt(j), + protoEvent.miSC_maybeWrapAt(j), + quant.miSC_maybeWrapAt(j), + doReset.miSC_maybeWrapAt(j) + ); + } + } + + reset { plbindefArray.do { |i| plbindefParEnvironment[i].reset } } + stop { plbindefArray.do { |i| plbindefParEnvironment[i].stop } } + clear { plbindefArray.do { |i| plbindefParEnvironment[i].clear } } +} + diff --git a/Classes/Patterns/PS.sc b/Classes/Patterns/PS.sc new file mode 100755 index 0000000..ad936d4 --- /dev/null +++ b/Classes/Patterns/PS.sc @@ -0,0 +1,141 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// It might look odd that copying is triggered twice in PSx patterns, but - +// especially important with event patterns: copying within the Pfunc function ensures +// that buffered items of the *source* are not altered and second copying +// (delegated to the MemoRoutine) ensures that items buffered in the PSx are not +// altered. It would of be possible to differentiate by defining two further +// copy flags. + + +PStream : Plazy { + var <>srcPat, <>length, <>lengthStream, <>bufSize, <>copyItems, <>copySets, <>memoRoutine; + + *new { |srcPat, length = inf, bufSize = 1, copyItems = 0, copySets = 1| + ^super.new.srcPat_(srcPat).length_(length).bufSize_(bufSize) + .copyItems_(copyItems).copySets_(copySets) + } + storeArgs { ^[srcPat, length, bufSize, copyItems, copySets] } + + embedInStream { | inval| + memoRoutine.isNil.if { + lengthStream = length.asStream; + // the MemoRoutine shouldn't be instantiated before streamification (allows dynamic scoping) + // new streams should refer to the same MemoRoutine + memoRoutine = MemoRoutine( + { |inval| srcPat.embedInStream(inval) }, + bufSize: bufSize, + copyItems: copyItems, + copySets: copySets + ) + }; + func = { |inval| + Pfinval(lengthStream.next(inval), Pfunc { memoRoutine.next(inval).miSC_copy(copyItems, copySets) }) + }; + ^func.value(inval).embedInStream(inval) + } + + at { |i| ^memoRoutine.lastValues[i] } + + lastValues { ^memoRoutine.lastValues } + + lastValue { ^memoRoutine.lastValues[0] } + + count { ^memoRoutine.count } + + bufSeq { |dropNils = true| + var seq = memoRoutine.lastValues.reverse; + ^dropNils.if { seq.reject(_.isNil) }{ seq } + } + +} + + +PS : PStream {} + +Pstream : PStream {} + +PSdup : PStream { + var <>psxPat; + + *new { |psxPat, length = inf, bufSize = 1, copyItems = 0, copySets = 1| + ^super.new( + psxPat.isKindOf(PStream).not.if { SimpleInitError("PSdup requires PSx source pattern").throw }; + Pfunc { psxPat.lastValue.miSC_copy(copyItems, copySets) }, length, bufSize, copyItems, copySets + ).psxPat_(psxPat); + } + storeArgs { ^[psxPat, length, bufSize, copyItems, copySets] } +} + + +PSrecur : PStream { + var <>start, <>recurFunc, <>recurFuncStream; + *new { |recurFunc, length = inf, bufSize, start, copyItems = 0, copySets = 1| + + // adapt bufSize if not given + bufSize = bufSize ?? { + (start.isNil || (start.isKindOf(SequenceableCollection).not)).if { 1 }{ start.size }; + }; + // make start an array + (start.notNil && (start.isKindOf(SequenceableCollection).not)).if { start = [start] }; + ^super.new(nil, length, bufSize, copyItems, copySets).start_(start).recurFunc_(recurFunc) + } + storeArgs { ^[recurFunc, length, bufSize, start, copyItems, copySets] } + + embedInStream { | inval| + var replaceSize; + // the MemoRoutine shouldn't be instantiated before streamification (allows dynamic scoping) + // new streams should refer to the same MemoRoutine + memoRoutine.isNil.if { + lengthStream = length.asStream; + recurFuncStream = recurFunc.asStream; + + memoRoutine = MemoRoutine({ |inval| + Pfunc { + recurFuncStream.next.(memoRoutine.lastValues, memoRoutine.count).miSC_copy(copyItems, copySets) + }.embedInStream(inval) + }, + bufSize: bufSize, + copyItems: copyItems, + copySets: copySets + ); + start.notNil.if { + replaceSize = min(start.size, memoRoutine.lastValues.size); + replaceSize.do { |i| memoRoutine.lastValues[i] = start[start.size - 1 - i] }; + }; + }; + + func = { |inval| + Pfinval(lengthStream.next(inval), Pfunc { memoRoutine.next(inval) }) + }; + ^func.value(inval).embedInStream(inval) + } + +} + + + + diff --git a/Classes/Patterns/PSPdiv.sc b/Classes/Patterns/PSPdiv.sc new file mode 100755 index 0000000..b118d2a --- /dev/null +++ b/Classes/Patterns/PSPdiv.sc @@ -0,0 +1,210 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +PSPdiv : Pspawner { + classvar <>shiftDelta = 1e-8; + var <>pulse, <>evPat, <>div, <>divBase, <>divType; + + *new { |pulse, evPat, div = 1, divBase = 1, divType = \seq| + ^super.newCopyArgs.pspDivInit(pulse, evPat, div, divBase, divType) + } + + pspDivInit { |pulse, evPat, div, divBase, divType| + var divPS, divBasePS, divTypePS, sizes, maxSize; + + pulse.isKindOf(Number).if { pulse = Pn(pulse) }; + evPat = evPat.asArray; + div = div.asArray; + divBase = divBase.asArray; + divType = divType.asArray; + // div, divBase and divTape: size must be equal and equal 1 or evPat.size + + sizes = [evPat, div, divBase, divType].collect(_.size).asSet; + maxSize = sizes.maxItem; + + ((sizes.size > 2) or: { (sizes.size == 2) && (sizes.includes(1).not) }).if { + SimpleInitError("sizes of evPat, div, divBase, divType must equal 1 or n > 1").throw; + }; + + routineFunc = { |sp| + var pulseStr = pulse.asStream; + var evPats = evPat.miSC_unifySize(maxSize) + .collect { |p| p.isKindOf(Pattern).if { p.asStream }{ p } }; + var divStrs = div.miSC_unifySize(maxSize).collect { |x| x.asStream }; + var divBaseStrs = divBase.miSC_unifySize(maxSize).collect(_.asStream); + var divTypeStrs = divType.miSC_unifySize(maxSize).collect(_.asStream); + var pulseCount = 0; + var queueCount = 0; + // queue orders queueCount + var queue = PriorityQueue.new; + var nextPulseDurs = []; + var nextDiv, nextDivBase, nextDivType, s, + nextDivs, nextDivBases, nextDivTypes, + currentIndices, nextDivBaseDur, maxDivBase, + nextEvPatDurs, nextQueueStep, nextPulseStep, + nextPulseDurSum, nextPulseDurSums, suspendIndices; + + (0..evPats.size-1).do { |i| queue.put(0, i) }; + + block { |break| loop { + s = 0; + nextDiv = nil; + nextDivBase = nil; + nextDivType = nil; + nextDivs = nil; + nextDivBases = nil; + nextDivTypes = nil; + currentIndices = nil; + nextDivBaseDur = nil; + maxDivBase = nil; + nextEvPatDurs = nil; + nextQueueStep = nil; + nextPulseStep = nil; + nextPulseDurSum = nil; + nextPulseDurSums = nil; + suspendIndices = nil; + + while { queueCount == queue.topPriority }{ + currentIndices = currentIndices.asArray ++ (queue.pop); + }; + + (currentIndices.size != 0).if { + currentIndices.sort; + + maxDivBase = 0; + + currentIndices.do { |i| + nextDiv = divStrs[i].next; + nextDivBase = divBaseStrs[i].next; + nextDivType = divTypeStrs[i].next; + + ((nextDiv.isNil) || (nextDivBase.isNil) || (nextDivType.isNil)).if { + suspendIndices = suspendIndices.add(i); + }{ + + nextDivs = nextDivs.add(nextDiv); + nextDivBases = nextDivBases.add(nextDivBase); + nextDivTypes = nextDivTypes.add(nextDivType); + + (nextDivBase > maxDivBase).if { maxDivBase = nextDivBase }; + + (evPats[i].isKindOf(Function) or: + { (evPats[i].state == 0) || (evPats[i].state == 5) }).if { + queue.put( + (nextDivType == 'par').if { 1 }{ nextDivBase } + queueCount, + i + ); + }{ + suspendIndices = suspendIndices.add(i); + } + }; + }; + + currentIndices.removeAll(suspendIndices); + + (currentIndices.size == 0).if { + sp.suspendAll; + break.value; + }; + + (queueCount >= pulseCount).if { + nextPulseStep = maxDivBase; + nextPulseDurs = pulseStr.nextN(nextPulseStep); + }{ + nextPulseStep = maxDivBase - pulseCount + queueCount; + nextPulseDurs = nextPulseDurs ++ + pulseStr.nextN(nextPulseStep); + }; + + nextQueueStep = (queue.topPriority - queueCount).round.asInteger; + + nextPulseDurSums = nextPulseDurs.collect { |d| s = s + d }; + nextPulseDurSum = nextPulseDurSums[nextQueueStep - 1]; + + // sprout subpatterns + + currentIndices.do { |i, j| + nextDivBaseDur = nextPulseDurSums[nextDivBases[j] - 1]; + nextEvPatDurs = nextEvPatDurs + .add(this.miSC_calcDivs(nextDivs[j], nextDivBaseDur)); + + sp.par( + Pspawner { |sp| + (i * shiftDelta).wait; + + sp.par( + evPats[i].isKindOf(Function).if { + evPats[i].( + nextEvPatDurs[i], + nextDivs[j], + nextDivBases[j], + nextDivTypes[j] + ) + }{ + Pbindf( + Pfin(nextEvPatDurs[i].size, evPats[i]), + \dur, Pseq(nextEvPatDurs[j]) + ) + } + ) + } + ); + } + + }{ + sp.suspendAll; + break.value; + }; + queueCount = queueCount + nextQueueStep; + pulseCount = pulseCount + nextPulseStep; + nextPulseDurs = nextPulseDurs.drop(nextQueueStep); + nextPulseDurSum.wait; + } } + }; + ^this + } + + miSC_calcDivs { |div, nextDivBaseDur| + ^case + { div.isKindOf(Integer) }{ (nextDivBaseDur / div) ! div } + { div.isKindOf(Array) }{ div.normalizeSum * nextDivBaseDur } + { div.isKindOf(Function) }{ div.(nextDivBaseDur) } + { true }{ "div item of wrong type: must be Integer, Array or Function" } + } + +} + + + ++SequenceableCollection { + miSC_unifySize { |size| + ^(this.size != size).if { this ++ (this[0] ! (size - 1)) }{ this } + } +} + ++Object { + miSC_unifySize { |size| ^this ! size } +} + diff --git a/Classes/Patterns/PbindFx.sc b/Classes/Patterns/PbindFx.sc new file mode 100644 index 0000000..4f06cdf --- /dev/null +++ b/Classes/Patterns/PbindFx.sc @@ -0,0 +1,111 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +AbstractPbindFx : Pchain { + + classvar <>defaultSourceCleanupDelay = 0.3; + classvar <>defaultFxCleanupDelay = 0.05; + classvar <>defaultCleanupDt = 0.2; + + *new { |pbindData ...fxData| + var srcPat, fxPat, pairs, fxEventsPat; + + srcPat = case { pbindData.isKindOf(SequenceableCollection) }{ + Pbind(*pbindData) + }{ pbindData.isKindOf(Pattern) }{ + pbindData + }{ true }{ + SimpleInitError("pbindData must be event pattern or list of patternpairs").throw + }; + srcPat = srcPat.eventShortcuts; + + fxEventsPat = Ptuple(fxData.collect { |fxDataI, i| + var fxPatI = case { fxDataI.isKindOf(SequenceableCollection) }{ + Pbind(*fxDataI) + }{ fxDataI.isKindOf(Pattern) }{ + fxDataI + }{ true }{ + SimpleInitError("fxData item must be event pattern or list of patternpairs").throw + }; + + // need to apply here as data is encapsulated in Events + // normal replacement mechanism wouldn't work + + fxPatI = fxPatI.eventShortcuts; + + // start not before fx demanded with Pclutch_PbindFx + // (slight change of Pclutch default behaviour) + Pclutch_PbindFx( + Pevent(fxPatI <> Pbind(\cleanupDelay, defaultFxCleanupDelay)), + Pfunc { |e| e.fxOrder.miSC_getClutch(i+1) }, + 0 + ) + }); + + fxPat = Pbind( + \fxDataSize, fxData.size, + \defaultFxOrder, [0], + [\fxOrder, \fxPredecessors, \fxSuccessors], + Pfunc { |e| + (e.fxOrder ?? { e.defaultFxOrder }).value.miSC_getFxOrderData(e.fxDataSize); + }, + \type, \pbindFx, + \fxEvents, fxEventsPat + ); + + ^super.new(fxPat, srcPat); + } + +} + +PbindFx : AbstractPbindFx { + + *new { |pbindData ... fxData| + ^super.new(pbindData, *fxData) + } +} + +// receiver supposed to be clutchIndex + ++ Integer { + miSC_getClutch { |index| + ^(index == this).if { true }{ false } + } +} + +// receiver supposed to be clutchIndices + ++ SequenceableCollection { + + miSC_getClutch { |index| + ^this.includes(index).if { true }{ false } + } + + miSC_atKey { |key| + var i = this.indexOf(key); + ^i !? { this[i + 1] } + } +} + diff --git a/Classes/Patterns/Pclutch_PbindFx.sc b/Classes/Patterns/Pclutch_PbindFx.sc new file mode 100644 index 0000000..bd4f1dc --- /dev/null +++ b/Classes/Patterns/Pclutch_PbindFx.sc @@ -0,0 +1,53 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +Pclutch_PbindFx : FilterPattern { + var <>connected, <>start; + *new { arg pattern, connected = true, start; + ^super.new(pattern).connected_(connected).start_(start) + } + storeArgs { ^[ pattern, connected, start ] } + embedInStream { arg inval; + var clutchStream = connected.asStream; + var stream = pattern.asStream; + var startStream = start.asStream; + var outval, clutch, hasStarted = false; + while { + clutch = clutchStream.next(inval); + clutch.notNil + } { + if(clutch === true or: { clutch == 1 }) { + hasStarted = true; + outval = stream.next(inval); + if(outval.isNil) { ^inval }; + inval = outval.yield; + } { + hasStarted.not.if { outval = startStream.next(inval) }; + inval = outval.copy.yield; + }; + } + } +} + diff --git a/Classes/Patterns/extDictionary.sc b/Classes/Patterns/extDictionary.sc new file mode 100644 index 0000000..c2c58e8 --- /dev/null +++ b/Classes/Patterns/extDictionary.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++ Dictionary { + miSC_getEnvir { ^this } +} + + diff --git a/Classes/Patterns/extEvent.sc b/Classes/Patterns/extEvent.sc new file mode 100755 index 0000000..6dce475 --- /dev/null +++ b/Classes/Patterns/extEvent.sc @@ -0,0 +1,34 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Event { + + on { + this[\dur] ?? { this.put(\dur, inf) }; + ^this.play + } + off { |releaseTime| ^this.release(releaseTime) } + +} diff --git a/Classes/Patterns/extIdentityDictionary.sc b/Classes/Patterns/extIdentityDictionary.sc new file mode 100644 index 0000000..6b78b20 --- /dev/null +++ b/Classes/Patterns/extIdentityDictionary.sc @@ -0,0 +1,47 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + ++IdentityDictionary { + + miSC_replaceKeys { |dict| + var r; + this.copy.keysValuesDo { |k, v| + r = dict.at(k); + r.notNil.if { + this.put(r, v); + this.removeAt(k); + } + } + } + + eventShortcuts { + ^EventShortcuts.miSC_replaceShortcuts(this) + } + +} + + + diff --git a/Classes/Patterns/extObject.sc b/Classes/Patterns/extObject.sc new file mode 100644 index 0000000..b1b7b9a --- /dev/null +++ b/Classes/Patterns/extObject.sc @@ -0,0 +1,43 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Object { + miSC_check { ^(this.value == 1) || (this.value == true) } + + miSC_getEnvir { + SimpleInputError("Only Dictionary or Symbols 'top' ('t') or 'current' ('c') " ++ + "allowed as envir input.").throw; + } + + miSC_repTypeFactor { |type = inf| ^type } + + miSC_applyNaryFuncProxy { |funcProxy...args| ^funcProxy.source.value(this, *args) } + + miSC_makeLacePat { + ^PL(this) + } + + eventShortcuts { ^this } +} + diff --git a/Classes/Patterns/extObject_2.sc b/Classes/Patterns/extObject_2.sc new file mode 100755 index 0000000..96e6427 --- /dev/null +++ b/Classes/Patterns/extObject_2.sc @@ -0,0 +1,55 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Set { + miSC_copy { |copyItems = 0, copySets = 1| + var obj = (copySets == 1).if { this.shallowCopy }{ this }; + ^obj.array_(obj.array.collect(_.miSC_copy(copyItems))) } +} + + ++Object { + + miSC_getCopyCode { + ^IdentityDictionary[ + (0 -> 0), + (1 -> 1), + (2 -> 2), + (false -> 0), + (true -> 1), + (\false -> 0), + (\true -> 1), + (\deep -> 2), + ].at(this) ? 0 + } + + + miSC_copy { |copyItems = 0| + ^(copyItems == 2).if { this.deepCopy }{ (copyItems == 1).if { this.copy }{ this } } + } + + + miSC_maybeWrapAt { ^this } +} + diff --git a/Classes/Patterns/extPattern.sc b/Classes/Patterns/extPattern.sc new file mode 100644 index 0000000..c4456eb --- /dev/null +++ b/Classes/Patterns/extPattern.sc @@ -0,0 +1,39 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + ++Pattern { + miSC_repTypeFactor { |type| ^1 } + + eventShortcuts { + ^Pcollect({ |e| EventShortcuts.miSC_replaceShortcuts(e) }, this) + } + + symplay { |dict, clock, protoEvent, quant, maxNull = 128| + ^PsymNilSafe(this, dict ?? { currentEnvironment }, maxNull).play(clock, protoEvent, quant) + } + +} + diff --git a/Classes/Patterns/extPbindFx_1.sc b/Classes/Patterns/extPbindFx_1.sc new file mode 100644 index 0000000..8006528 --- /dev/null +++ b/Classes/Patterns/extPbindFx_1.sc @@ -0,0 +1,250 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++SequenceableCollection { + + miSC_makeStartFxBundle { |successors, fxOrderPositions, fxBuses, splitBuses, + splitFactors, fxEvents, srcGroupId, fxGroupId, firstFxIds, lastFxIds, baseLatency, + cleanupDelaySums, latestCleanupIndex, gateDelay, out, freePerGroup, timingOffset, lag, server| + + var outBus, msgFunc, hasAmp, hasFreq, removeSyms, actionNum, referenceId, + fxPairs, fxBundle, fxIds, fxEvent, startFxBundle, freeFxBundle; + + // fxOrder is receiver + this.do { |fxIndex, i| + fxEvent = fxEvents[fxIndex-1]; + + // prepare fxPairs from msgFunc + // fx should not have default amp and freq + + msgFunc = SynthDescLib.global[fxEvent[\fx].asSymbol].msgFunc; + fxPairs = fxEvent.use { msgFunc.valueEnvir }; + + hasAmp = #[amp, db].any { |x| fxEvent.keys.includes(x) }; + hasFreq = #[degree, note, midinote, freq].any { |x| fxEvent.keys.includes(x) }; + + removeSyms = [\out] ++ (hasAmp.not.if { \amp }) ++ (hasFreq.not.if { \freq }); + fxPairs = fxPairs.miSC_collectEvalWithoutKeyPairs(removeSyms, fxEvent); + + outBus = (i < (this.size-1)).if { + // index shift as split arrays also refer to src + (splitFactors[i+1] > 1).if { + splitBuses[i+1].index + }{ + (successors[fxIndex].first == \o).if { + out.asControlInput + }{ + fxBuses[fxOrderPositions[successors[fxIndex].first] - 1].index + } + } + }{ + out.asControlInput + }; + + fxBundle = fxPairs.asArray.flop; + fxIds = fxIds.add({ server.nextNodeID } ! (fxBundle.size)); + + // if fx has an array value do generate multiple fx + + fxBundle.do { |fxMsg, j| + + #firstFxIds, lastFxIds, referenceId, actionNum = i.miSC_fxIdRank( + firstFxIds, lastFxIds, fxIds.last[j], srcGroupId + ); + + startFxBundle = startFxBundle ++ [ + ([\s_new, fxEvent[\fx].asSymbol, fxIds.last[j], actionNum, referenceId] ++ + fxMsg ++ (fxBuses[i].isNil).if { [] }{ [\in, fxBuses[i].index] } ++ + [\out, outBus]).asOSCArgArray + ]; + + }; + + // latest fx synth per chain will be freed anyway by group (i == latestCleanupIndex), + // others will be freed before if ~freePerGroup == true + + ((i == (latestCleanupIndex - 1)) or: { freePerGroup.not }).if { + freeFxBundle = ((i == (latestCleanupIndex - 1)).if { + [11, fxGroupId] + }{ + [11, fxIds.last.last] + }).flop; + + schedBundleArrayOnClock(timingOffset + gateDelay, + thisThread.clock, freeFxBundle, lag, server, + baseLatency + cleanupDelaySums[i+1] + ) + }; + }; + + ^startFxBundle + } + + + + + miSC_makeStartZeroBundle { |predecessors, successors, fxOrderPositions, fxBuses, splitBuses, + splitFactors, fxNum, srcGroupId, fxGroupId, baseLatency, cleanupDelaySums, latestCleanupIndex, + gateDelay, out, freePerGroup, timingOffset, lag, zeroSynthOverlap, server| + + var index, numChannels, fxZeroSynthIds, actionNum, referenceId, firstFxIds, + lastFxIds, predecessorsI, prependIndex, freeZeroBundle, startZeroBundle, + startSplitBundle, splitSynthIds, freeSplitBundle, fxOutIndices, splitName, channelNum, + startSplitZeroBundle, fxSplitZeroSynthIds, freeSplitZeroBundle; + + // this data structure keeps track of zero synth ordering in *fxGroup*, + // needed as zero synths are established before fx synths, + // relevant is first and last zero synth per fx slot + + firstFxIds = {} ! fxNum; + lastFxIds = {} ! fxNum; + + this.do { |fxIndex, i| + predecessorsI = predecessors[fxIndex].asArray; + + (predecessorsI.size != 0).if { + // prepare buses and zero synth ids + index = fxBuses[i].index; + numChannels = fxBuses[i].numChannels; + fxZeroSynthIds = numChannels.collect { server.nextNodeID }; + + predecessorsI.includes(0).if { + + // if fx reads from src, zero synth(s) must be before src (head of src group) + actionNum = 0; + startZeroBundle = startZeroBundle ++ fxZeroSynthIds.collect { |id, j| + [\s_new, \pbindFx_zero, id, actionNum, srcGroupId, "out", index + j] + }; + }{ + // find first fx in order which writes to this fx, + // zero synth(s) must must be before it + actionNum = 2; + + prependIndex = fxNum-1; + predecessorsI.do { |x| + (fxOrderPositions[x] - 1 < prependIndex).if { + prependIndex = fxOrderPositions[x] - 1 + } + }; + + fxZeroSynthIds.do { |id, j| + #firstFxIds, lastFxIds, referenceId, actionNum = prependIndex.miSC_zeroIdRank( + firstFxIds, lastFxIds, id, fxGroupId + ); + + startZeroBundle = startZeroBundle ++ [ + [\s_new, \pbindFx_zero, id, actionNum, referenceId, "out", index + j] + ] + } + } + }; + + // for latest fx synth (i == (latestCleanupIndex-1)) zero synth(s) are freed by group (freeFxBundle) + // other zero synths will be freed separately except if ~freePerGroup == true, + // freeing is scheduled with overlap + + ((i != (latestCleanupIndex - 1)) and: { freePerGroup.not and: { (predecessorsI.size != 0) } }).if { + freeZeroBundle = (fxZeroSynthIds.collect([11, _])); + schedBundleArrayOnClock(timingOffset + gateDelay, + thisThread.clock, freeZeroBundle, lag, server, + baseLatency + cleanupDelaySums[i+1] + zeroSynthOverlap + ); + }; + }; + + splitSynthIds = {} ! fxNum; + + splitFactors.do { |splitFactor, i| + + (splitFactor > 1).if { + splitSynthIds[i] = server.nextNodeID; + fxOutIndices = successors[i].asArray.collect { |s| + (s == \o).if { + out.asControlInput + }{ + fxBuses[fxOrderPositions[s] - 1].index + } + }; + + channelNum = fxBuses[fxOrderPositions[successors[i].first] - 1].numChannels; + splitName = \pbindFx_split_ ++ splitFactor.asString ++ "x" ++ channelNum.asString; + + (i == 0).if { + startSplitBundle = startSplitBundle ++ [ + [\s_new, splitName, splitSynthIds[i], 1, srcGroupId, + "in", splitBuses[i].index, "out", fxOutIndices].asOSCArgArray + ]; + fxSplitZeroSynthIds = splitBuses[i].numChannels.collect { server.nextNodeID }; + fxSplitZeroSynthIds.do { |id, j| + startSplitZeroBundle = startSplitZeroBundle ++ [ + [\s_new, \pbindFx_splitZero, id, 0, srcGroupId, + "out", splitBuses[i].index + j].asOSCArgArray + ] + } + }{ + #firstFxIds, lastFxIds, referenceId, actionNum = i.miSC_fxIdRank( + firstFxIds, lastFxIds, splitSynthIds[i], fxGroupId + ); + + startSplitBundle = startSplitBundle ++ [ + [\s_new, splitName, splitSynthIds[i], actionNum, referenceId, + "in", splitBuses[i].index, "out", fxOutIndices].asOSCArgArray + ]; + + fxSplitZeroSynthIds = splitBuses[i].numChannels.collect { server.nextNodeID }; + + fxSplitZeroSynthIds.do { |id, j| + #firstFxIds, lastFxIds, referenceId, actionNum = (i-1).miSC_zeroIdRank( + firstFxIds, lastFxIds, id, fxGroupId + ); + + startSplitZeroBundle = startSplitZeroBundle ++ [ + [\s_new, \pbindFx_splitZero, id, actionNum, referenceId, "out", + splitBuses[i].index + j] + ] + } + }; + + // free split and splitZero synths + // last splitFactor must not be other than 1 + + ((i != latestCleanupIndex) and: { freePerGroup.not }).if { + freeSplitBundle = [[11, splitSynthIds[i]]]; + schedBundleArrayOnClock(timingOffset + gateDelay, + thisThread.clock, freeSplitBundle, lag, server, + baseLatency + cleanupDelaySums[i] + ); + freeSplitZeroBundle = (fxSplitZeroSynthIds.collect([11, _])); + schedBundleArrayOnClock(timingOffset + gateDelay, + thisThread.clock, freeSplitZeroBundle, lag, server, + baseLatency + cleanupDelaySums[i] + zeroSynthOverlap + ); + } + } + }; + + ^[startZeroBundle, startSplitBundle, startSplitZeroBundle, firstFxIds, lastFxIds, splitSynthIds]; + } + +} diff --git a/Classes/Patterns/extPbindFx_2.sc b/Classes/Patterns/extPbindFx_2.sc new file mode 100644 index 0000000..9dadea3 --- /dev/null +++ b/Classes/Patterns/extPbindFx_2.sc @@ -0,0 +1,185 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Symbol { + + miSC_checkPbindFxBusMatch { |sym, firstIsSource = false, secondIsLast = false, + firstOtherBusArgs, secondOtherBusArgs| + + var firstOutputs = SynthDescLib.global[this].outputs; + var secondInputs = SynthDescLib.global[sym].inputs; + var secondOutputs = SynthDescLib.global[sym].outputs; + var firstInputs = SynthDescLib.global[this].inputs; + + var areFirstInputsOk, areFirstOutputsOk, areSecondInputsOk, areSecondOutputsOk, + firstOutNumberOfChannels, secondInNumberOfChannels, connIo, ioRef = `nil; + + var inSelector = { |io| io.type != LocalIn }; + var outSelector = { |io| io.type != LocalOut }; + + // crucial check for inputs/outputs: + // counting number of ioTypes (\in or \out), must be 1 + // looking if otherBusArgs allow further ins and outs + // ioRef gets the relevant connection between fxs in second call of ioCheck + + var ioCheck = { |inOutputs, ioType, ioRef, otherArgs| + var count = 0; + inOutputs.every { |io| + (io.startingChannel == ioType).if { ioRef.value = io; count = count + 1 }; + (io.startingChannel == ioType) or: { + otherArgs.isNil.if { false } { otherArgs.includes(io.startingChannel) }; + }; + } and: { count == 1 } + }; + + firstInputs = firstInputs.select(inSelector); + firstOutputs = firstOutputs.select(outSelector); + secondInputs = secondInputs.select(inSelector); + secondOutputs = secondOutputs.select(outSelector); + + areFirstInputsOk = firstIsSource.if { + firstOtherBusArgs.isNil.if { + firstInputs.size == 0 + }{ + firstInputs.every { |io| firstOtherBusArgs.includes(io.startingChannel) } + } + }{ + // if first node (received symbol) denotes effect, + //its inputs are checked within other match + true + }; + + areFirstOutputsOk = ioCheck.(firstOutputs, \out, ioRef, firstOtherBusArgs); + areSecondInputsOk = ioCheck.(secondInputs, \in, ioRef, secondOtherBusArgs); + + connIo = ioRef.value; + + // now connIo is only relevant if all 4 checks are ok + + areSecondOutputsOk = secondIsLast.if { + ioCheck.(secondOutputs, \out, ioRef, secondOtherBusArgs) + }{ + // if second node denotes effect before last effect, + // its outputs are checked within other match + true + }; + + ((areFirstInputsOk && areFirstOutputsOk && areSecondInputsOk && areSecondOutputsOk) and: { + (firstOutputs[0].numberOfChannels) <= (connIo.numberOfChannels) + }).not.if { + SimpleInitError("PbindFx bus mismatch, source and fx synths must match " ++ + "in/out conventions: \n\n" ++ + ".) \tFor source and fx SynthDefs there must be only one out ugen " ++ + "using 'out' as bus arg, \n" ++ + "\tLocalOut is allowed, other out ugens can be admitted by \\otherBusArgs. \n" ++ + ".) \tSource SynthDefs must not have in ugens, except LocalIn or \n" ++ + "\tthey are admitted by \\otherBusArgs. \n" ++ + ".) \tFx synths must read from buses with ugen In.ar(in, ...) " ++ + "refering to the bus arg 'in', \n\tthere must not be other in ugens " ++ + "within the fx SynthDef, \n\texcept LocalIn or they are admitted by \\otherBusArgs.\n" ++ + ".) \tNumber of out channels of preceeding source / fx synth" ++ + " must not be greater than \n" ++ + "\tthe number of the following fx synth's in channels,\n\tthis is checked for " ++ + "all connections of an fx graph." + ).throw; + }; + ^connIo.first.numberOfChannels + } +} + + ++SequenceableCollection { + + // order as receiver + miSC_getFxBusData { |predecessors, successors, fxOrderPositions, fxEvents, srcInstrument, + otherBusArgs, cleanupDelay, server| + var cleanupDelaySums = [0], fxBuses, splitBuses, + splitFactors, fxNum = this.size; + + // 0 (src) can have a split, but last fx in topo order cannot + splitBuses = {} ! fxNum; + splitFactors = {} ! fxNum; + + splitFactors[0] = successors[0].asArray.size; + (splitFactors[0] > 1).if { + splitBuses[0] = Bus.audio( + server, + SynthDescLib.global[srcInstrument].outputs.first.numberOfChannels + ) + }; + + this.do { |fxIndex, i| + var inSize, inst, prevInst, prevInsts, fxEvent = fxEvents[fxIndex-1], maxPrevCleanupDelaySum = 0; + inst = (fxEvents[fxIndex-1][\fx]).asSymbol; + + prevInsts = predecessors[fxIndex].asArray.collect { |j| + // to get the new cleanupDelaySum, we have to add to the + // max cleanupDelaySum of the predecessors + + // all cleanupDelaySums are calculated without source cleanupDelay first, + // which is added afterwards, that way branches with no ins have proper cleanupDelay also (think) + var k = fxOrderPositions[j]; + + (cleanupDelaySums[k] >= maxPrevCleanupDelaySum).if { + maxPrevCleanupDelaySum = cleanupDelaySums[k] + }; + + (j == 0).if { srcInstrument }{ (fxEvents[j - 1][\fx]).asSymbol } + }; + + prevInsts.do { |prevInst| + inSize = prevInst.miSC_checkPbindFxBusMatch( + inst, + i == 0, + i+1 == fxNum, + (i == 0).if { otherBusArgs }{ fxEvents[this[i-1]-1][\otherBusArgs] }, + fxEvents[fxIndex-1][\otherBusArgs] + ) + }; + + // is nil if there is no in + fxBuses = fxBuses.add(inSize.notNil.if { Bus.audio(server, inSize) }); + + cleanupDelaySums = cleanupDelaySums.add( + fxEvent[\cleanupDelay] + maxPrevCleanupDelaySum + ); + + (i < (this.size-1)).if { + splitFactors[i+1] = successors[fxIndex].asArray.size; + (splitFactors[i+1] > 1).if { + splitBuses[i+1] = Bus.audio( + server, + SynthDescLib.global[inst].outputs.first.numberOfChannels; + ) + } + } + }; + // adjust cleanupDelaySums to source (see comments above) + cleanupDelaySums = cleanupDelaySums + cleanupDelay; + ^[fxBuses, splitBuses, splitFactors, cleanupDelaySums] + } +} + + diff --git a/Classes/Patterns/extPbindFx_3.sc b/Classes/Patterns/extPbindFx_3.sc new file mode 100644 index 0000000..bd155ca --- /dev/null +++ b/Classes/Patterns/extPbindFx_3.sc @@ -0,0 +1,305 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Object { + + miSC_checkFxOrder { ^false } + + miSC_fxOrderWarnString { + ^"wrong fxOrder data type: \n" ++ + "It must be an Integer, SequenceableCollection or IdentityDictionary, \n" ++ + "see PbindFx help for details and examples.\n" + } + + miSC_getFxOrderData { |fxDataSize, maxSplitSize = 8, doCheck = true| + + // this makes an input check if doCheck == true + + // receiver can be + // (1) an Integer indicating an effect (or source) + // (2) a SequenceableCollection indicating an effect chain + // (3) an IdentityDictionary indicating an effect graph, + + // output is an array [x,y,z] with + // x: topological ordering of graph, + // this is either [0] (no effect) or an array of fx indices where 0 as head is dropped + + // y: an IdentityDictionary of predesessors (node \o added for 'out') + // z: an IdentityDictionary of successors (node \o added for 'out') + // main job is case (3) + + ^doCheck.if { + this.miSC_checkFxOrder(fxDataSize, maxSplitSize) + }{ + true + }.if { + + this.miSC_getFxOrders; + }{ + "".postln; "NO FX APPLIED".warn; + this.miSC_fxOrderWarnString.postln; + [[0], IdentityDictionary[\o -> 0], IdentityDictionary[0 -> \o]] + } + } +} + + ++Integer { + + miSC_checkFxOrder { |maxIndex| ^(this >= 0) and: { this <= maxIndex } } + + miSC_fxOrderWarnString { + ^"fxOrder given as Integer failed: \n" ++ + "It must be greater or equal 0 and smaller or equal size of fxData, \n" ++ + "see PbindFx help for other possibilities of definition and examples.\n" + } + + miSC_getTopoOrder { + ^(this == 0).if { [0] }{ [this] } + } + + miSC_getPredecessors { + ^(this == 0).if { + IdentityDictionary[\o -> 0] + }{ + IdentityDictionary[\o -> this, this -> 0] + } + } + + miSC_getSuccessors { + ^(this == 0).if { + IdentityDictionary[0 -> \o] + }{ + IdentityDictionary[0 -> this, this -> \o] + } + } + + miSC_getFxOrders { + ^[this.miSC_getTopoOrder, this.miSC_getPredecessors, this.miSC_getSuccessors] + } +} + ++SequenceableCollection { + + miSC_checkFxOrder { |maxIndex| + ^this.every { |x,i| + x.isInteger and: { (x >= 1) or: { (i == 0) and: { x == 0 } } + and: { x <= maxIndex } + } + } + } + + miSC_fxOrderWarnString { + ^"fxOrder given as SequenceableCollection failed: \n" ++ + "It must contain Integers greater or equal 1 and smaller " ++ + "or equal size of fxData, \n" ++ + "see PbindFx help for other possibilities of definition and examples.\n" + } + + miSC_getTopoOrder { + ^(this[0] == 0).if { + (this.size == 1).if { [0] }{ this.drop(1) } + }{ + this + } + } + + miSC_getPredecessors { + var dict = IdentityDictionary(); + this.do { |x,i| + (i != 0).if { dict.put(x, this[i-1]) } + }; + dict.put(this[0], 0); + dict.put(\o, this.last); + ^dict + } + + miSC_getSuccessors { + var dict = IdentityDictionary(); + this.do { |x,i| + dict.put(x, (i != (this.size-1)).if { this[i+1] }{ \o }) + }; + dict.put(0, this[0]); + ^dict + } + + miSC_getFxOrders { + ^[this.miSC_getTopoOrder, this.miSC_getPredecessors, this.miSC_getSuccessors] + } +} + + ++IdentityDictionary { + + miSC_checkFxOrder { |maxIndex, maxSplitSize| + ^this.miSC_keysValuesEvery { |k,v,i| + k.isInteger and: { k >= 0 } and: { k <= maxIndex } and: { + (v.isInteger and: { v >= 1 } and: { v <= maxIndex }) or: { v == \o } or: { + v.isKindOf(Collection) and: { + v.every { |x| + (x.isInteger and: { x >= 1 } and: { x <= maxIndex }) or: + { x == \o } + } and: { + v.size == v.asSet.size + } and: { + v.size <= maxSplitSize + } + } + } + } + } + } + + miSC_fxOrderWarnString { + ^"fxOrder given as IdentityDictionary failed: \n" ++ + "Keys must be Integers greater or equal 0 and smaller or equal size of " ++ + "fxData, \nvalues must be Integers greater or equal 1 and smaller " ++ + "or equal size of fxData or Symbol \o or \n" ++ + "SequenceableCollection thereof, see PbindFx help for other possibilities " ++ + "of definition and examples.\n" + } + + miSC_keysValuesEvery { |function| + this.keysValuesDo { |k,v,i| if (function.value(k,v,i).not) { ^false } } + ^true; + } + + miSC_keysValuesAny { |function| + this.keysValuesDo { |k,v,i| if (function.value(k,v,i)) { ^true } } + ^false; + } + + miSC_putAppend { |k, v| + this[k].isNil.if { + this.put(k,v) + }{ + this[k].isKindOf(Collection).if { + this[k] = this[k].add(v) + }{ + this.put(k, [this[k], v]) + } + }; + ^this + } + + miSC_removeDrop { |k, v| + this[k].isNil.if { + this + }{ + (this[k].isKindOf(Collection) and: { this[k].size >= 2 }).if { + this[k].remove(v) + }{ + this.put(k, nil) + } + }; + ^this + } + + // already checked: well-defined + miSC_getPredecessors { + var dict = IdentityDictionary.new; + this.keysValuesDo { |k, v| + v.isKindOf(Collection).if { + v.do { |x| dict.miSC_putAppend(x, k) } + }{ + dict.miSC_putAppend(v, k) + } + }; + ^dict + } + + // adds \o (~ out) to nodes, which have no successors + miSC_getSuccessors { + var graph = this.as(IdentityDictionary).deepCopy, vals; + vals = graph.values; + + vals.do { |v| + v.isKindOf(Collection).if { + v.do { |w| + (graph[w].isNil and: { w != \o }).if { + graph.miSC_putAppend(w, \o) + } + } + }{ + (graph[v].isNil and: { v != \o }).if { graph.miSC_putAppend(v, \o) } + } + } + ^graph + } + + // we suppose there are no doubled edges, this has been checked in miSC_checkFxOrder + miSC_getTopoOrder { |predecessors, successors| + var graph, node, order, nodesWithoutIns; + + graph = successors ?? { this.miSC_getSuccessors }; + predecessors = predecessors ?? { graph.miSC_getPredecessors }; + + // if 0 is in graph, we want an ordering with it at head + graph.keys.includes(0).if { + // already checked that 0 is no successor + nodesWithoutIns = nodesWithoutIns.add(0) + }; + + graph.keysValuesDo { |k,v| + (k != 0).if { + predecessors[k].isNil.if { nodesWithoutIns = nodesWithoutIns.add(k) } + } + }; + + while { nodesWithoutIns.size != 0 }{ + node = nodesWithoutIns[0]; + nodesWithoutIns = nodesWithoutIns.drop(1); + order = order.add(node); + graph[node].asArray.do { |succ| + predecessors.miSC_removeDrop(succ, node); + predecessors[succ].isNil.if { + nodesWithoutIns = nodesWithoutIns.add(succ) + }; + }; + graph.put(node, nil); + }; + ^(graph.size == 0).if { order.reject(_==\o) } + } + + miSC_getFxOrders { + var order, predecessors, successors, col; + + successors = this.miSC_getSuccessors; + predecessors = successors.miSC_getPredecessors; + + order = this.miSC_getTopoOrder(predecessors.deepCopy, successors.deepCopy); + ((order.size > 1) and: (order[0] == 0)).if { order.remove(0) }; + + ^order.isNil.if { + "".postln; "NO FX APPLIED".warn; + "cyclic graph !".postln; + [[0], IdentityDictionary[\o -> 0], IdentityDictionary[0 -> \o]] + }{ + [order, predecessors, successors] + } + } +} + + diff --git a/Classes/Patterns/extPbindFx_4.sc b/Classes/Patterns/extPbindFx_4.sc new file mode 100644 index 0000000..319a0c2 --- /dev/null +++ b/Classes/Patterns/extPbindFx_4.sc @@ -0,0 +1,87 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// subroutines used to establish a proper ordering of +// fx synths, zero synths, split synths and zero synths for split synths + ++Integer { + + // receiver is index + // find the right position for zero synth(s) #i (related to inbus of fx # i), + // this order is established before fitting in fx synths + + miSC_zeroIdRank { |firstFxIds, lastFxIds, nodeId, groupId| + var idAtTail = false, j, referenceId, actionNum; + firstFxIds[this].isNil.if { + j = this + 1; + while { (j <= (firstFxIds.size-1)) and: { idAtTail.not } }{ + firstFxIds[j].notNil.if { + referenceId = firstFxIds[j]; + idAtTail = true; + actionNum = 2; + }; + j = j + 1; + }; + idAtTail.not.if { + referenceId = groupId; + actionNum = 1; + }; + lastFxIds[this] = nodeId; + }{ + referenceId = firstFxIds[this]; + actionNum = 2; + }; + firstFxIds[this] = nodeId; + ^[firstFxIds, lastFxIds, referenceId, actionNum] + } + + + // receiver is index + // find the right position for split and fx synth(s) #i + + miSC_fxIdRank { |firstFxIds, lastFxIds, nodeId, groupId| + var idAtHead = false, j, referenceId, actionNum; + lastFxIds[this].isNil.if { + j = this - 1; + while { (j >= 0) and: { idAtHead.not } }{ + lastFxIds[j].notNil.if { + referenceId = lastFxIds[j]; + idAtHead = true; + }; + j = j - 1; + }; + idAtHead.not.if { referenceId = groupId }; + lastFxIds[this] = nodeId; + }{ + referenceId = lastFxIds[this]; + }; + actionNum = 3; + lastFxIds[this] = nodeId; + ^[firstFxIds, lastFxIds, referenceId, actionNum] + } + +} + + diff --git a/Classes/Patterns/extSequenceableCollection.sc b/Classes/Patterns/extSequenceableCollection.sc new file mode 100644 index 0000000..4f474eb --- /dev/null +++ b/Classes/Patterns/extSequenceableCollection.sc @@ -0,0 +1,65 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++SequenceableCollection { + miSC_makeLacePat { + ^Ppatlace(this.collect(_.miSC_makeLacePat), inf) + } + miSC_makeLaceList { |repeats = inf| + ^this.collect(_.miSC_makeLacePat) + } + + ev { + var ev = (); + this.pairsDo { |k,v| ev.put(k, ev.use { v.() }) }; + ^ev + } + on { ^this.ev.on } + + pa { + var a; + this.pairsDo { |k,v| + a = a.add(k); + a = a.add(v.isKindOf(Function).if { Pfunc { |e| e.use { v.() } } }{ v }); + }; + ^a + } + + p { ^Pbind(*this.pa)} + pm { |sym| ^Pmono(sym, *this.pa)} + pma { |sym| ^PmonoArtic(sym, *this.pa)} + pbf { |sym| ^Pbindef(sym, *this.pa)} + + pp { |clock, protoEvent, quant| ^this.p.play(clock, protoEvent, quant)} + ppm { |sym, clock, protoEvent, quant| ^this.pm(sym).play(clock, protoEvent, quant)} + ppma { |sym, clock, protoEvent, quant| ^this.pma(sym).play(clock, protoEvent, quant)} + ppbf { |sym, clock, protoEvent, quant| ^this.pbf(sym).play(clock, protoEvent, quant)} + + eventShortcuts { ^this.collect(_.eventShortcuts) } + + miSC_maybeWrapAt { |i| ^this.wrapAt(i) } + +} + diff --git a/Classes/Patterns/extStream.sc b/Classes/Patterns/extStream.sc new file mode 100644 index 0000000..f372f3d --- /dev/null +++ b/Classes/Patterns/extStream.sc @@ -0,0 +1,29 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + ++Stream { + miSC_repTypeFactor { |type| ^1 } +} diff --git a/Classes/Patterns/extSymbol.sc b/Classes/Patterns/extSymbol.sc new file mode 100644 index 0000000..ce7969c --- /dev/null +++ b/Classes/Patterns/extSymbol.sc @@ -0,0 +1,40 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Symbol { + miSC_getEnvir { + ((this == \c) or: { this == \current }).if { + ^currentEnvironment + }{ + ((this == \t) or: { this == \top }).if { + ^topEnvironment + }{ + SimpleInputError("Only Symbols 'top' ('t') or 'current' ('c') " ++ + "allowed as envir symbols.").throw; + } + } + } +} + diff --git a/Classes/Sieves/Psieve.sc b/Classes/Sieves/Psieve.sc new file mode 100755 index 0000000..2a4dd09 --- /dev/null +++ b/Classes/Sieves/Psieve.sc @@ -0,0 +1,363 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +Psieve : Pattern { + + classvar <>limit = 65536; + + var <>items, <>offsets, <>limit, <>maxLength, + <>withOffsets = false, <>doSum = false, <>op, <>difIndex; + + + embedInStream { |inval| + var goOn = true, last, count = 0, counts, itemStreams, opStream, nextOp, + yielder, next, maxLengthNum, minIndices, min, leftIndices, counter, + difIndexStream, nextDifIndex, indicesQueue = PriorityQueue.new, + // faster than storing indices in an array + minIndicesDict = IdentityDictionary.new; + + offsets.isNil.if { offsets = 0!(items.size) }; + + // if Sieve is passed adjust offset + items.do { |item, i| + item.isKindOf(Sieve).if { + // set to nil with empty Sieve + offsets[i] = (item.mode == \points).if { + (item.list.size != 0).if { offsets[i] + item.list[0] }; + }{ + item.offset.notNil.if { offsets[i] + item.offset }; + } + } + }; + + itemStreams = items.collect(_.miSC_streamifySieveItems); + counts = offsets; + counts.do { |offset, i| + ((offset.notNil) and: { offset <= limit }).if { + indicesQueue.put(offset, i); + leftIndices = leftIndices.add(i); + } + }; + + opStream = op.asStream; + difIndexStream = difIndex.asStream; + maxLengthNum = maxLength.value; + + leftIndices.notNil.if { while { goOn }{ + + // partial sums stored in PriorityQueue + min = indicesQueue.topPriority.round.asInteger; + minIndices = indicesQueue.pop; + + // if more than one min is found, indices are collected in Dictionary + while { indicesQueue.topPriority == min }{ + minIndices.isInteger.if { + minIndicesDict.clear; + minIndices = minIndicesDict.put(minIndices, true) + }; + minIndicesDict.put(indicesQueue.pop, true) + }; + + // yielder function chooses output type + yielder = { + doSum.if { + inval = min.yield; + last = min; + count = count + 1; + }{ + last.notNil.if { + inval = (min - last).yield; + count = count + 1; + }; + last = min + } + }; + + nextOp = opStream.next; + nextOp.isNil.if { ^inval }; + + // operator decides what happens at this partial sum + case + { nextOp == \u } + { yielder.() } + { nextOp == \s } + { (minIndices.size == items.size) if: { yielder.() } } + { nextOp == \sd } + { minIndices.isInteger if: { yielder.() } } + { nextOp == \d } + { + // select the receiver of logical difference + difIndex.isNil.if { + nextDifIndex = 0 + }{ + nextDifIndex = difIndexStream.next; + nextDifIndex.isNil.if { ^inval }; + }; + (minIndices == nextDifIndex) if: { yielder.() } + }; + + // faster than minIndices.asArray.do { ... + counter = { |i| + next = itemStreams[i].next; + next.notNil.if { + counts[i] = counts[i] + next; + (counts[i] <= limit).if { indicesQueue.put(counts[i], i) } + }; + (next.isNil or: { counts[i] > limit }).if { leftIndices.remove(i) }; + }; + minIndices.isInteger.if { counter.(minIndices) }{ minIndices.keysDo(counter.(_)) }; + + case + { nextOp == \u } + { (leftIndices.size == 0).if { goOn = false } } + { nextOp == \s } + { (leftIndices.size < (items.size)).if { goOn = false } } + { nextOp == \sd } + { (leftIndices.size == 0).if { goOn = false } } + { nextOp == \d } + { (leftIndices[0] != 0).if { goOn = false } }; + + (count >= maxLengthNum).if { goOn = false } + } }; + ^inval + } + + + *miSC_checkOffsetGenList { |genList, limit| + var offsets, items, classes = [Integer, Pattern, Stream, Sieve]; + genList.size.do { |i| + i.even.if { + items = items.add(genList[i]) + }{ + offsets = offsets.add(genList[i]) + } + }; + items.every { |x| classes.any(x.isKindOf(_)) }.not.if { + SimpleInitError( + "Sieve base items must be Integers > 0, Sieves or: \n" ++ + "Patterns or Streams to make Integers > 0 (intervals)" + ).throw + }; + items.any { |x| x.isKindOf(Integer) and: { x <= 0 } }.if { + SimpleInitError("Integers as sieve bases must be > 0").throw + }; + offsets.every { |x| x.isKindOf(Integer) }.not.if { + SimpleInitError("Offsets must be Integers").throw + }; + limit = limit ?? { this.limit }; + ^[items, offsets, limit] + } + + + *miSC_checkGenList { |genList, limit| + var items = genList, classes = [Integer, Pattern, Stream, Sieve]; + + items.every { |x| classes.any(x.isKindOf(_)) }.not.if { + SimpleInitError( + "Sieve base items must be Integers > 0, Sieves or: \n" ++ + "Patterns or Streams to make Integers > 0 (intervals)" + ).throw + }; + items.any { |x| x.isKindOf(Integer) and: { x <= 0 } }.if { + SimpleInitError("Integers as sieve bases must be > 0").throw + }; + limit = limit ?? { this.limit }; + ^[items, limit] + } +} + + +PSVunion : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, true, \u) + } +} + + +PSVunion_o : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, true, \u) + } +} + +PSVunion_i : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, false, \u) + } +} + +PSVunion_oi : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, false, \u) + } +} + + +PSVsect : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, true, \s) + } +} + + +PSVsect_o : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, true, \s) + } +} + +PSVsect_i : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, false, \s) + } +} + +PSVsect_oi : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, false, \s) + } +} + + + +PSVsymdif : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, true, \sd) + } +} + + +PSVsymdif_o : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, true, \sd) + } +} + +PSVsymdif_i : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, false, \sd) + } +} + +PSVsymdif_oi : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, false, \sd) + } +} + + + +PSVdif : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, true, \d) + } +} + + +PSVdif_o : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, true, \d) + } +} + +PSVdif_i : Psieve { + *new { |genList, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, false, \d) + } +} + +PSVdif_oi : Psieve { + *new { |genList, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, false, \d) + } +} + + +PSVop : Psieve { + *new { |genList, op = \u, difIndex = 0, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, true, op, difIndex) + } +} + + +PSVop_o : Psieve { + *new { |genList, op = \u, difIndex = 0, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, true, op, difIndex) + } +} + +PSVop_i : Psieve { + *new { |genList, op = \u, difIndex = 0, maxLength = inf, limit| + var items, lim; + #items, lim = this.miSC_checkGenList(genList, limit); + ^super.newCopyArgs(items, nil, lim, maxLength, false, false, op, difIndex) + } +} + +PSVop_oi : Psieve { + *new { |genList, op = \u, difIndex = 0, maxLength = inf, limit| + var items, offsets, lim; + #items, offsets, lim = this.miSC_checkOffsetGenList(genList, limit); + ^super.newCopyArgs(items, offsets, lim, maxLength, true, false, op, difIndex) + } +} + + diff --git a/Classes/Sieves/Sieve.sc b/Classes/Sieves/Sieve.sc new file mode 100755 index 0000000..697f1f3 --- /dev/null +++ b/Classes/Sieves/Sieve.sc @@ -0,0 +1,601 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +Sieve { + + classvar <>limit = 65536; + + var > { |addOffset| ^this.shift(addOffset) } + + + shiftTo { |targetOffset| + ^(mode == \points).if { + (list.size != 0).if { this.shift(targetOffset - list[0]) }{ this } + }{ + offset.isNil.if { this }{ this.shift(targetOffset - offset) } + } + } + + >>! { |targetOffset| ^this.shiftTo(targetOffset) } + + shiftToZero { ^list.shiftTo(0) } + + + // we want to copy the Sieve's list too + copy { ^this.deepCopy } + + // new Sieve, same list object + weakCopy { ^this.superPerform(\copy) } + + // take over mode and offset from Sieve and pass an appropriate array + copyWith { |seqCollection, withCheck = true| + var new = this.weakCopy; + + seqCollection.isKindOf(SequenceableCollection).not.if { + SimpleInitError( + "copyWith expects SequenceableCollection as first arg" + ).throw + }; + + seqCollection.every(_.isInteger).not.if { + SimpleInitError( + "SequenceableCollection must consist of Integers" + ).throw + }; + + (mode == \points).if { + withCheck.if { + (seqCollection.every { |point, i| + (point > 0) and: { (i == 0) or: { point > seqCollection[i-1] } } + }).not.if { + SimpleInitError( + "With mode = \points SequenceableCollection " ++ + "must be strictly ascending" + ).throw + } + }; + }{ + withCheck.if { + seqCollection.every(_>0).not.if { + SimpleInitError( + "With mode = \intervals SequenceableCollection" ++ + "must consist of positive Integers" + ).throw + } + }; + } + ^new.miSC_setList(seqCollection.asList) + } + + // apply operator or Function to List and pass the result + // to a new Sieve with copied mode and offset + copyApplyTo { |operator, withCheck = true| + ^this.copyWith(operator.applyTo(this.list), withCheck) + } + + // equality also considers different modes + == { |that| + ^(this.mode == that.mode).if { + list == that.list and: { this.offset == that.offset } + }{ + (this.mode == \points).if { + this == that.weakCopy.toPoints + }{ + that == this.weakCopy.toPoints + } + } + } + + + // segment methods are most efficient for receiver of mode == \points, + // output is new Sieve object of mode \points anyway + segmentGreaterEqual { |lo| + var index, point, sieve, doCheck = true; + sieve = Sieve.newEmpty; + ^(mode == \points).if { + (list.size != 0).if { + index = list.miSC_lowestIndexForWhichGreaterEqual(lo); + index.notNil.if { sieve.miSC_setList(list.copyRange(index, list.size-1)) } + }; + sieve + }{ + offset.notNil.if { + point = offset; + (offset >= lo).if { sieve.list.add(point); doCheck = false }; + + list.do { |interval| + point = point + interval; + doCheck.if { + (point >= lo).if { doCheck = false; sieve.list.add(point) } + }{ + sieve.list.add(point) + } + } + }; + sieve + }.miSC_setMode(\points); + } + + segmentLessEqual { |hi| + var index, point, sieve; + sieve = Sieve.newEmpty; + ^(mode == \points).if { + (list.size != 0).if { + index = list.miSC_highestIndexForWhichLessEqual(hi); + index.notNil.if { sieve.miSC_setList(list.copyRange(0, index)) } + }; + sieve + }{ + offset.notNil.if { + point = offset; + index = 0; + while { index <= (list.size-1) }{ + point = point + list[index]; + (point <= hi).if { sieve.list.add(point) }{ index = list.size - 1 }; + index = index + 1; + } + }; + sieve + }.miSC_setMode(\points); + } + + // extra method is more efficient than to apply segmentLessEqual and segmentGreaterEqual + segmentBetweenEqual { |lo, hi| + var index, point, sieve, doLoCheck = true, loIndex, hiIndex; + sieve = Sieve.newEmpty; + ^(lo > hi).if { + sieve + }{ + (mode == \points).if { + (list.size != 0).if { + loIndex = list.miSC_lowestIndexForWhichGreaterEqual(lo); + hiIndex = list.miSC_highestIndexForWhichLessEqual(hi); + (loIndex.isNil or: { hiIndex.isNil }).if { + sieve + }{ + sieve.miSC_setList(list.copyRange(loIndex, hiIndex)) + } + }{ + sieve + } + }{ + offset.notNil.if { + point = offset; + index = 0; + while { index <= (list.size-1) }{ + point = point + list[index]; + + doLoCheck.if { + (point >= lo).if { + doLoCheck = false; + (point <= hi).if { + sieve.list.add(point) + }{ + index = list.size - 1 + }; + } + }{ + (point <= hi).if { + sieve.list.add(point) + }{ + index = list.size - 1 + }; + }; + index = index + 1; + } + }; + sieve + } + }.miSC_setMode(\points); + } + + + segmentGreater { |lo| ^this.segmentGreaterEqual(lo + 1) } + + >=! { |lo| ^this.segmentGreaterEqual(lo) } + >! { |lo| ^this.segmentGreaterEqual(lo + 1) } + + + segmentLess { |hi| ^this.segmentLessEqual(hi - 1) } + + <=! { |hi| ^this.segmentLessEqual(hi) } + =! { |bounds| ^this.segmentBetweenEqual(*bounds) } + <>! { |bounds| ^this.segmentBetweenEqual(bounds[0] + 1, bounds[1] - 1) } + + + + printOn { arg stream; + if (stream.atLimit, { ^this }); + stream << "Sieve(" ; + stream << (this.mode.asString ++ ", "); + (this.mode == \intervals).if { stream << (this.offset.asString ++ ", ") }; + list.printOn(stream); + stream << ")" ; + } + + storeOn { arg stream; + var thisMode; + if (stream.atLimit, { ^this }); + + stream << "[ " ; + list.storeItemsOn(stream); + stream << " ]" ; + + stream << ".toSieve("; + stream << offset.asString; + stream << ", \\"; + thisMode = this.mode.asString; + stream << thisMode; + stream << ", \\"; + stream << thisMode; + stream << ")"; + } + + // private + + // These setters don't check the Sieve's state, + // the user should not directly set mode and offset. + + miSC_setMode { |v| mode = v } + miSC_setOffset { |v| offset = v } + miSC_setList { |v| list = v } + + miSC_sieveOp { |args, withOffsets = false, doSum = false, op| + var goOn = true, last, counts, items, offsets, limit, next, + minIndices, min, leftIndices, counter, minIndicesDict = IdentityDictionary.new, + indicesQueue = PriorityQueue.new; + + #items, offsets, limit = (withOffsets.if { + this.miSC_checkOffsetArgs(args); + }{ + this.miSC_checkArgs(args); + }); + + offsets.isNil.if { offsets = 0!(items.size) }; + + // adjust offset if Sieve is passed + items.do { |item, i| + item.isKindOf(Sieve).if { + // set to nil with empty Sieve + offsets[i] = (item.mode == \points).if { + (item.list.size != 0).if { offsets[i] + item.list[0] }; + }{ + item.offset.notNil.if { offsets[i] + item.offset }; + } + } + }; + + items = items.collect(_.miSC_streamifySieveItems); + counts = offsets; + counts.do { |offset, i| + ((offset.notNil) and: { offset <= limit }).if { + indicesQueue.put(offset, i); + leftIndices = leftIndices.add(i); + } + }; + + mode = doSum.if { \points }{ \intervals }; + + leftIndices.notNil.if { while { goOn }{ + // partial sums stored in PriorityQueue + min = indicesQueue.topPriority.round.asInteger; + minIndices = indicesQueue.pop; + + // if more than one min is found, indices are collected in Dictionary + while { indicesQueue.topPriority == min }{ + minIndices.isInteger.if { + minIndicesDict.clear; + minIndices = minIndicesDict.put(minIndices, true) + }; + minIndicesDict.put(indicesQueue.pop, true) + }; + + // operator decides what happens at this partial sum + doSum.if { + case + { op == \u } + { list.add(min); last = min } + { op == \s } + { (minIndices.size == items.size).if { list.add(min); last = min } } + { op == \sd } + { minIndices.isInteger.if { list.add(min); last = min } } + { op == \d } + { (minIndices == 0).if { list.add(min); last = min } } + }{ + case + { op == \u } + { + last.notNil.if { list.add(min - last) }{ offset = min }; + last = min + } + { op == \s } + { + (minIndices.size == items.size).if { + last.notNil.if { list.add(min - last) }{ offset = min }; + last = min + } + } + { op == \sd } + { + minIndices.isInteger.if { + last.notNil.if { list.add(min - last) }{ offset = min }; + last = min + } + } + { op == \d } + { + (minIndices == 0).if { + last.notNil.if { list.add(min - last) }{ offset = min }; + last = min + } + } + }; + + // faster than minIndices.asArray.do { ... + counter = { |i| + next = items[i].next; + next.notNil.if { + counts[i] = counts[i] + next; + (counts[i] <= limit).if { indicesQueue.put(counts[i], i) } + }; + (next.isNil or: { counts[i] > limit }).if { leftIndices.remove(i) }; + }; + minIndices.isInteger.if { counter.(minIndices) }{ minIndices.keysDo(counter.(_)) }; + + case + { op == \u } + { (leftIndices.size == 0).if { goOn = false } } + { op == \s } + { (leftIndices.size < (items.size)).if { goOn = false } } + { op == \sd } + { (leftIndices.size == 0).if { goOn = false } } + { op == \d } + { (leftIndices[0] != 0).if { goOn = false } }; + } }; + + ^this + } + + + miSC_checkOffsetArgs { |args| + var offsets, items, limit, maxSize = args.size, + classes = [Integer, Pattern, Stream, Sieve]; + args.size.odd.if { + limit = args.last.value; + limit.isKindOf(Integer).not.if { + SimpleInitError( + "limit -- given as last item of an odd number " ++ + "of args --\n must be or eveluate to an Integer").throw + }; + maxSize = maxSize - 1 + }{ + limit = Sieve.limit + }; + maxSize.do { |i| + i.even.if { + items = items.add(args[i]) + }{ + offsets = offsets.add(args[i]) + } + }; + items.every { |x| classes.any(x.isKindOf(_)) }.not.if { + SimpleInitError( + "Sieve base items must be Integers > 0, Sieves or: \n" ++ + "Patterns or Streams to make Integers > 0 (intervals)" + ).throw + }; + items.any { |x| x.isKindOf(Integer) and: { x <= 0 } }.if { + SimpleInitError("Integers as sieve bases must be > 0").throw + }; + offsets.every { |x| x.isKindOf(Integer) }.not.if { + SimpleInitError("Offsets must be Integers").throw + }; + ^[items, offsets, limit] + } + + + miSC_checkArgs { |args| + var items = args, limit, + classes = [Integer, Pattern, Stream, Sieve]; + + args.last.isKindOf(Ref).if { + items = items.drop(-1); + // if new gets a Ref eval twice + limit = args.last.value.value; + limit.isKindOf(Integer).not.if { + SimpleInitError("limit -- given as last arg wrapped " ++ + "into a Ref object --\n" ++ + "must be an Integer" + ).throw + } + }{ + limit = Sieve.limit + }; + items.every { |x| classes.any(x.isKindOf(_)) }.not.if { + SimpleInitError( + "Sieve base items must be Integers > 0, Sieves or: \n" ++ + "Patterns or Streams to make Integers > 0 (intervals)" + ).throw + }; + items.any { |x| x.isKindOf(Integer) and: { x <= 0 } }.if { + SimpleInitError("Integers as sieve bases must be > 0").throw + }; + ^[items, nil, limit] + } +} + ++SequenceableCollection { + + // iterated bisection, expects ordered list + miSC_lowestIndexForWhichGreaterEqual { |lo| + var goOn = true, loIndex = 0, hiIndex = this.size - 1, newIndex, index; + + (this[hiIndex] < lo).if { goOn = false }; + (this[loIndex] >= lo).if { goOn = false; index = 0 }; + + while { goOn }{ + ((hiIndex - loIndex) <= 1).if { goOn = false; index = hiIndex }; + newIndex = div(hiIndex + loIndex, 2); + + (this[newIndex] == lo).if { goOn = false; index = newIndex }; + (this[newIndex] < lo).if { loIndex = newIndex }{ hiIndex = newIndex }; + }; + + ^index + } + + // iterated bisection, expects ordered list + miSC_highestIndexForWhichLessEqual { |hi| + var goOn = true, loIndex = 0, hiIndex = this.size - 1, newIndex, index; + + (this[loIndex] > hi).if { goOn = false }; + (this[hiIndex] <= hi).if { goOn = false; index = hiIndex }; + + while { goOn }{ + ((hiIndex - loIndex) <= 1).if { goOn = false; index = loIndex }; + newIndex = div(hiIndex + loIndex, 2); + + (this[newIndex] == hi).if { goOn = false; index = newIndex }; + (this[newIndex] > hi).if { hiIndex = newIndex }{ loIndex = newIndex }; + }; + + ^index + } + +} + diff --git a/Classes/Sieves/lcmExtensions.sc b/Classes/Sieves/lcmExtensions.sc new file mode 100644 index 0000000..5c0e01e --- /dev/null +++ b/Classes/Sieves/lcmExtensions.sc @@ -0,0 +1,117 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Integer { + + lcmByGcd { |...args| + var lcm, thr = 2 ** 31 - 1, postWarning = false, returnNil = false; + (args.size == 0).if { ^(this == 0).if { 0 }{ this.abs } }; + (args.every { |i| i.isKindOf(Integer) }).not.if { "lcmByGcd requires Integers".error }; + args.any(_ == 0).if { ^0 }; + lcm = args.inject(this, { |x, y, i| + // z must be float for reliable threshold check, thus '/' instead of 'div' + var z = x / gcd(x.isFloat.if { x.round.asInteger }{ x }, y) * y; + (z > thr).if { + (i < (args.size-1)).if { + ("exceeding int32 bound within iteration, " ++ + "reduce number of args or try lcmByFactors").warn; + returnNil = true; + }; + postWarning = true; + }; + z + }); + returnNil.if { ^nil }; + ^postWarning.if { + "exceeding int32 bound, returning float".warn; + lcm + }{ + lcm.round.asInteger + } + } + + lcmByFactors { |...args| + var lcm, f, factors, argFactors, argListFactors, lcmFactors, + lcmFactorDict = IdentityDictionary.new, + postWarning = false, thr = 2 ** 31 - 1; + + (args.size == 0).if { ^(this == 0).if { 0 }{ this.abs } }; + (args.every { |i| i.isKindOf(Integer) }).not.if { "lcmByGcd requires Integers".error }; + args.any(_ == 0).if { ^0 }; + + factors = this.abs.factors; + argListFactors = args.abs.collect(_.factors); + + f = { |dict| + { |x| + var m = dict.at(x); + dict.put(x, m.isNil.if { 1 }{ m + 1 }); + } + }; + factors.do(f.(lcmFactorDict)); + + // collect prime factors and occurences + argListFactors.do { |argFactors| + var argFactorDict = IdentityDictionary.new; + argFactors.do(f.(argFactorDict)); + + argFactorDict.keysValuesDo{ |k,v,i| + var m = lcmFactorDict.at(k); + lcmFactorDict.put(k, m.isNil.if { v }{ max(m,v) }) + }; + }; + + lcmFactors = []; + lcmFactorDict.keysValuesDo { |k,v| v.do { lcmFactors = lcmFactors.add(k) } }; + lcmFactors.sort; + + // threshold check, if result exceeds int32 bound return float + lcmFactors.do { |x,i| + (lcmFactors.size > 1).if { + (i == 0).if { + lcm = x.asFloat; + }{ + lcm = lcm * x; + (lcm > thr).if { postWarning = true }; + } + }{ + ^[x, lcmFactors, [factors, argListFactors]] + } + }; + ^postWarning.if { + "exceeding int32 bound, returning float".warn; + [lcm, lcmFactors, [factors, argListFactors]] + }{ + [lcm.round.asInteger, lcmFactors, [factors, argListFactors]] + } + } + +} + ++SequenceableCollection { + + lcmByGcd { ^this[0].lcmByGcd(*this[1..]) } + lcmByFactors { ^this[0].first.lcmByFactors(*this[1..]) } +} + diff --git a/Classes/Sieves/periods.sc b/Classes/Sieves/periods.sc new file mode 100644 index 0000000..31ac08f --- /dev/null +++ b/Classes/Sieves/periods.sc @@ -0,0 +1,160 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++SequenceableCollection { + + + miSC_isSymmetricRange { |i, j| + var count = 0, limit = div(j - i, 2); + + while { count <= limit }{ + (this[i + count] != this[j - count]).if { ^false }; + count = count + 1 + }; + ^true + } + + miSC_isQuasiSymmetricRange { |i, j| + ^this.miSC_isSymmetricRange(i + 1, j) + } + + // expects j >= i + miSC_symmetryType { |i, j| + ^((j == i) or: { + (0..j - i - 1).every { |k| this[i + k + 1] == this[i] } + }).if { + 3 + }{ + this.miSC_isSymmetricRange(i, j).if { + 2 + }{ + this.miSC_isQuasiSymmetricRange(i, j).if { 1 }{ 0 } + } + } + } + + miSC_smallestPeriodLength { + var length = 1, i, z = this.size; + + while { length + 1 <= z }{ + i = 0; + while { i + 1 <= z }{ + (this[i % length] != this[i]).if { i = z }; + i = i + 1; + (i == z).if { ^length } + }; + (length + 1 == z).if { + ^length + 1 + }{ + length = length + 1 + + } + }; + ^1 + } + + miSC_checkSymmetricPeriods { + var length = this.miSC_smallestPeriodLength, offset = 0, z = this.size, + type = 0, goOn = true, periods, symmetries, completions, halfPeriodStart, + symTypeSymbols = IdentityDictionary[ + 0 -> 'asym', + 1 -> 'quasisym', + 2 -> 'sym', + 3 -> 'identic' + ]; + + while { goOn }{ + type = this.miSC_symmetryType(offset, offset + length - 1); + (type != 0).if { + // if type is quasi-symmetric and length odd there might be a symmetric period + // starting from the middle - check if it exists and if it's in the range, + // if so prefer symmetric period representation + (length.odd and: { type == 1 }).if { + halfPeriodStart = offset + div(length, 2) + 1; + ((halfPeriodStart + length <= z) and: { + this[halfPeriodStart] == this[halfPeriodStart - 1] + }).if { type = 2; offset = halfPeriodStart }; + }; + goOn = false + }{ + offset = offset + 1 + }; + (offset + length > z).if { goOn = false }; + }; + + (type == 0).if { + offset = 0; + periods = this.clump(length); + symmetries = 0 ! periods.size; + completions = true ! periods.size; + + // check symmetry of incomplete period, it can be of any type + (periods.last.size != periods.first.size).if { + completions[periods.size - 1] = false; + symmetries[periods.size - 1] = + periods.last.miSC_symmetryType(0, periods.last.size - 1); + } + + }{ + periods = ((offset > 0).if { [this[0..offset-1].asArray] }) ++ (this.drop(offset).clump(length)); + completions = periods.collect { |p| p.size == length }; + symmetries = type ! periods.size; + + // check symmetries of incomplete periods, they can be of any type + completions.first.not.if { + symmetries[0] = periods[0].miSC_symmetryType(0, periods[0].size - 1) + }; + + completions.last.not.if { + symmetries[periods.size - 1] = + periods.last.miSC_symmetryType(0, periods.last.size - 1) + }; + }; + ^[periods, symmetries.collect { |i| symTypeSymbols[i] }, completions] + } + + miSC_checkCharacteristicPeriod { + var periods, symmetries, completions, index, offset; + #periods, symmetries, completions = this.miSC_checkSymmetricPeriods; + index = completions.indexOfEqual(true); + offset = (index > 0).if { periods.first.size }{ 0 }; + ^[ + periods[index], + offset, + periods[index].size.odd.if { \odd }{ \even }, + symmetries[index] + ] + } +} + + ++Sieve { + checkSymmetricPeriods { ^this.weakCopy.toIntervals.list.miSC_checkSymmetricPeriods } + checkCharacteristicPeriod { ^this.weakCopy.toIntervals.list.miSC_checkCharacteristicPeriod } + plotCharacteristicPeriod { + ^this.weakCopy.toIntervals.list.miSC_checkCharacteristicPeriod.at(0) + .toSieve(\intervals, \intervals).plot + } +} diff --git a/Classes/Sieves/streamifySieveItems.sc b/Classes/Sieves/streamifySieveItems.sc new file mode 100755 index 0000000..2b113f2 --- /dev/null +++ b/Classes/Sieves/streamifySieveItems.sc @@ -0,0 +1,48 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Sieve { + miSC_streamifySieveItems { + ^(this.list.size != 0).if { + (this.mode == \intervals).if { + Pseq(this.list).asStream + }{ + Pdiff(Pseq(this.list)).asStream + } + } + } +} + ++Pattern { + miSC_streamifySieveItems { ^this.asStream } +} + ++Integer { + miSC_streamifySieveItems { ^this.asStream } +} + ++Stream { + miSC_streamifySieveItems { ^this } +} diff --git a/Classes/Sieves/toSieve.sc b/Classes/Sieves/toSieve.sc new file mode 100755 index 0000000..35ad512 --- /dev/null +++ b/Classes/Sieves/toSieve.sc @@ -0,0 +1,115 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Object { + miSC_isPointSel { ^((this == \points) or: { this == \p }) } + miSC_isIntervalSel { ^((this == \intervals) or: { this == \i }) } +} + ++Integer { + toSieve { ^Sieve.newEmpty.miSC_setList(List[this]).miSC_setMode(\points) } +} + + + ++SequenceableCollection { + + toSieve { |fromMode = \points, toMode = \points, addOffset = 0, withCheck = true| + + var sieve, newOffset, pointCol, intervalCol; + + addOffset.isInteger.not.if { + SimpleInitError("Argument addOffset must be Integer").throw + }; + this.every(_.isInteger).not.if { + SimpleInitError( + "SequenceableCollection must consist of Integers" + ).throw + }; + + case { fromMode.miSC_isPointSel }{ + pointCol = List.newUsing(this + addOffset); + intervalCol = pointCol.differentiate.drop(1); + withCheck.if { + intervalCol.every(_>0).not.if { + SimpleInitError( + "With fromMode = \points SequenceableCollection " ++ + "must be strictly ascending" + ).throw + } + }; + + case { toMode.miSC_isPointSel }{ + ^Sieve.newEmpty.miSC_setList(pointCol).miSC_setMode(\points) + } + { toMode.miSC_isIntervalSel }{ + newOffset = pointCol[0]; + ^Sieve.newEmpty.miSC_setList(intervalCol).miSC_setOffset(newOffset) + } + + { true }{ + SimpleInitError( + "Allowed Symbols for toMode: \points, \p, \intervals, \i" + ).throw + }; + } + { fromMode.miSC_isIntervalSel }{ + + withCheck.if { + this.every(_>0).not.if { + SimpleInitError( + "With fromMode = \intervals SequenceableCollection " ++ + "must consist of positive Integers" + ).throw + } + }; + + case { toMode.miSC_isPointSel }{ + sieve = Sieve.newEmpty.miSC_setMode(\points); + sieve.list.add(addOffset); + this.do { |interval| var point = interval + sieve.list.last; sieve.list.add(point) }; + ^sieve + } + { toMode.miSC_isIntervalSel }{ + ^Sieve.newEmpty.miSC_setList(this).miSC_setOffset(addOffset) + } + + { true }{ + SimpleInitError( + "Allowed Symbols for toMode: " ++ + "\points, \p, \intervals, \i" + ).throw + }; + } + + { true }{ + SimpleInitError( + "allowed Symbols for fromMode: \points, \p, \intervals, \i" + ).throw + }; + + } +} + diff --git a/Classes/VarGui/SimpleInitError.sc b/Classes/VarGui/SimpleInitError.sc new file mode 100644 index 0000000..92bb5a4 --- /dev/null +++ b/Classes/VarGui/SimpleInitError.sc @@ -0,0 +1,41 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +SimpleInitError : Error { + + var <>class; + + errorString { + ^"INPUT ERROR in building an instance of " ++ class.asString ++ ":" + } + + reportError { + "".postln; + this.errorString.postln; + "".postln; + what.postln; + "".postln; + } +} diff --git a/Classes/VarGui/SimpleInputError.sc b/Classes/VarGui/SimpleInputError.sc new file mode 100644 index 0000000..181a5c0 --- /dev/null +++ b/Classes/VarGui/SimpleInputError.sc @@ -0,0 +1,49 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +SimpleInputError : Error { + + var <>methodString; + + errorString { + ^"INPUT ERROR in method " ++ methodString ++ " :" + } + + method_ { |method| methodString = method.miSC_errorString; ^this } + + reportError { + "".postln; + this.errorString.postln; + "".postln; + what.postln; + "".postln; + } +} + + ++Method { + miSC_errorString { ^this.ownerClass.name.asString ++ "::" ++ this.name.asString } +} + + diff --git a/Classes/VarGui/VarGui.sc b/Classes/VarGui/VarGui.sc new file mode 100644 index 0000000..6b4471b --- /dev/null +++ b/Classes/VarGui/VarGui.sc @@ -0,0 +1,469 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +VarGui { + var <>varCtr, <>synthCtr, <>synthIDs, <>server, <>streams, <>synthCtrIndices, + <>varCtrNum, <>varNum, <>varColorNum, <>synthCtrNum, synthColorNum, + hasConnectedVarEnvirGroups, hasConnectedSynthCtrGroups, firstSynthCtrIndices, + <>varStrings, varCtrSizes, synthCtrSizes, <>synthCtrStrings, <>saveData, <>envirs, + <>varEnvirIndices, varEnvirGroups, assumePlaying, <>assumeRunning, + <>assumeEnded, envirs, streamEnvirs, window, colors, <>varCtrColorPairs, <>synthCtrColorPairs, <>synthCtrSliders, + <>varCtrSliders, <>synthSliderDict, <>varSliderDict, <>synthNameBoxes; + + *new { |varCtr, synthCtr, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, + assumePlaying, assumeRunning, assumeEnded, server| + ^super.new.init(varCtr, synthCtr, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, + assumePlaying, assumeRunning, assumeEnded, server); + } + *load { |pathname, filename, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, + assumePlaying, assumeRunning, assumeEnded, server| + var loadData = (pathname ++ filename).load; + ^super.new.init(loadData[0], loadData[1], stream, synth, clock, quant, varEnvirGroups ?? loadData[2], envir, + synthCtrGroups ?? loadData[3], assumePlaying, assumeRunning, assumeEnded, server); + } + *load_old { |pathname, filename, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, + assumePlaying, assumeRunning, assumeEnded, server| + var loadData = (pathname ++ filename).load; + ^super.new.init(loadData[0], loadData[1].select { |x,i| i.odd }, stream, synth, clock, quant, + varEnvirGroups ?? loadData[2], envir, synthCtrGroups ?? loadData[3], assumePlaying, + assumeRunning, assumeEnded, server); + } + init { |varCtr, synthCtr, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, + assumePlaying, assumeRunning, assumeEnded, server| + this.server = server ?? { Server.default }; + + this.checkArgs(varCtr, synthCtr, stream, synth, varEnvirGroups, envir, + synthCtrGroups, assumePlaying, assumeRunning, assumeEnded); + + saveData = [ + // varCtr, synthCtr may have been flattened, so store mapping info as groupings + // miSC_collectCopy for nested arrays with unclear pointer structure + this.varCtr.miSC_collectCopy, + this.synthCtr.miSC_collectCopy, + varEnvirGroups ?? { + ((this.varCtr.size != 0) and: { varEnvirIndices.maxItem > 0 }).if { + varEnvirIndices.miSC_groupingFromIndices + } + }, + synthCtrGroups ?? { + ((synthCtrSynthIndices.size != 0) and: { synthCtrSynthIndices.maxItem > 0 }).if { + synthCtrSynthIndices.miSC_groupingFromIndices + } + } + ]; + + this.varCtr.do { |item,i| + var x, envir; + (i % 2 == 0).if { + this.varCtr[i+1].every(_.isSequenceableCollection).if { + envir = envirs[varEnvirIndices[i.div(2)]]; + x = envir[item]; + varCtrSizes = varCtrSizes.add(this.varCtr[i+1].size); + // build array in this envir with this name if not already there + ((x.isSequenceableCollection) and: { x.size == (this.varCtr[i+1].size) }).not.if { + envir[item] = Array.newClear(this.varCtr[i+1].size) + } + }{ + varCtrSizes = varCtrSizes.add(1); + }; + } + }; + + this.synthCtr.do { |item,i| + i.even.if { + this.synthCtr[i+1].every(_.isSequenceableCollection).if { + synthCtrSizes = synthCtrSizes.add(this.synthCtr[i+1].size); + }{ + synthCtrSizes = synthCtrSizes.add(1); + }; + synthCtrIndices = synthCtrIndices.add((synths[synthCtrSynthIndices[i.div(2)]]).miSC_getCtrIndex(item)); + } + }; + + // number of variables (keys) counting multiple keys but disregarding arrays: + varNum = this.varCtr.size.div(2); + + // number of variable controls counting multiple keys and regarding arrays: + varCtrNum = varCtrSizes.asArray.sum; + streamPlayerNum = streams.size; + + // number of synth controls counting multiple keys in different synths and regarding arrays: + synthCtrNum = synthCtrSizes.asArray.sum; + synthPlayerNum = synths.size; + + clocks = case + { clock.isNil }{ streams.collect {|x| x.clock ?? TempoClock.default } } + { clock.isSequenceableCollection }{ clock.collect {|x,i| x ?? streams[i].clock ?? TempoClock.default } } + { clock.isKindOf(Clock) }{ clock!(streamPlayerNum) }; + + quants = case + { quant.isNil }{ Quant.default!(streamPlayerNum) } + { quant.isSequenceableCollection }{ quant.collect(_.asQuant) } + { true }{ quant.asQuant!(streamPlayerNum) }; + + ^this + } + + + + gui { |sliderHeight = 18, sliderWidth, labelWidth = 75, numberWidth = 45, + sliderType = \standard, sliderMode = \jump, playerHeight = 18, precisionSpan = 10, stepEqualZeroDiv = 100, + tryColumnNum = 1, allowSynthsBreak = true, allowVarsBreak = true, allowSynthBreak = true, + allowArrayBreak = true, allowEnvirBreak = true, minPartitionSize = 0, + sliderPriority = \var, playerPriority = \stream, streamPlayerGroups, synthPlayerGroups, comboPlayerGroups, + font = "Helvetica", colorsLo, colorsHi, colorDeviation, ctrButtonGreyCenter, ctrButtonGreyDev, greyMode = false, + varColorGroups, synthColorGroups, name, updateNow = true, + sliderFontHeight = 12, playerFontHeight = 12, maxWindowWidth = 1500, maxWindowHeight = 700| + var windowName, tempColors, totalHeight, totalWidth, heightK, + minSliderFontHeight = 10, maxSliderFontHeight = 16, minFontSliderHeight = 12, maxFontSliderHeight = 24, + + cview, pview, pviewBounds, varColorNum, synthColorNum, colorNum, + colorDeviationDefault = 0.12, greyModeColorDeviationDefault = 0.0, varColorGroupsWasNil, groups, + colorsLoDefault = 0.25, greyModeColorsLoDefault = 0.4, colorsHiDefault = 0.7, greyModeColorsHiDefault = 0.6, + ctrButtonGreyCenterDefault = 0.5, ctrButtonGreyDevDefault = 0.8, greyModeCtrButtonGreyCenterDefault = 0.5, + greyModeCtrButtonGreyDevDefault = 0.65, + + synthNumWidth = 20, leftMargin = 40, columnIndent = 40, + rightMargin = 40, upperMargin = 30, lowerMargin = 30, gap = 3, + maxColumnNum, columnNum, possibleColumnBreakIndices, maxSliderWidth = 270, minSliderWidth = 100, + columnBreakIndices, effectiveSliderWidth, sliderSectionHeight = 0, + + xPosMin = 100, xPosMax = 500, yPosMin = 100, yPosMax = 500, + fontColor = Color.black, colorAreaUsage = 0.25, colorSteps = 1000, numColorExp = 0.4, k; + + window.notNil.if { SimpleInitError("Only one gui window from one VarGui at a time").class_(VarGui).throw; }; + + // div inits + + varColorGroups.notNil.if { varCtrNum.miSC_checkColorGroups(varColorGroups) }; + synthColorGroups.notNil.if { synthCtrNum.miSC_checkColorGroups(synthColorGroups) }; + + colorDeviation = colorDeviation ?? { + (varColorGroups.notNil || synthColorGroups.notNil).if { + 0 + }{ + greyMode.if { greyModeColorDeviationDefault }{ colorDeviationDefault } + } + }; + + + (greyMode && (varColorGroups.notNil || synthColorGroups.notNil)).if { + SimpleInitError("If a color grouping is passed greyMode must not be true").throw; + }; + + varColorGroupsWasNil = varColorGroups.isNil; + + // overrule standard color grouping scheme if one color grouping is given + varColorGroups = varColorGroups ?? { + groups = this.initVarCtrColorGroups; + synthColorGroups.isNil.if { groups }{ groups.flatten(1).collect(_.asArray) } + }; + synthColorGroups = synthColorGroups ?? { + groups = this.initSynthCtrColorGroups; + varColorGroupsWasNil.if { groups }{ groups.flatten(1).collect(_.asArray) } + }; + + + // check if wslib slider classes are known for respective sliderType + case + { (sliderType == \smooth) } + { + \EZSmoothSlider.asClass.isNil.if { + SimpleInitError("EZSmoothSlider unknown, wslib not installed ?").throw; + } + } + { (sliderType == \round) } + { + \EZRoundSlider.asClass.isNil.if { + SimpleInitError("EZRoundSlider unknown, wslib not installed ?").throw; + } + } + { sliderType == \standard }{ } + { true } + { SimpleInitError("sliderType must be one of \standard, \smooth or \round, "" ++ "" + last both need wslib installed") }; + case + { (sliderMode == \move) } + { + (sliderType == \standard).if { + SimpleInitError("sliderMode \move only with EZSmoothSlider or EZRoundSlider (wslib)").throw; + } + } + + { sliderMode == \jump }{ } + { true } + { SimpleInitError("sliderType must be one of \jump or \move, "" ++ "" + latter needs wslib installed") }; + + varCtrColorPairs = varCtrNum.miSC_colorDeviationPairs(varColorGroups); + synthCtrColorPairs = synthCtrNum.miSC_colorDeviationPairs(synthColorGroups); + + maxColumnNum = ((maxWindowWidth - leftMargin - rightMargin + columnIndent) / (minSliderWidth + labelWidth + gap)).floor; + tryColumnNum = min(tryColumnNum, maxColumnNum).asInteger; + + possibleColumnBreakIndices = this.possibleColumnBreakIndices( + sliderPriority, allowSynthsBreak, allowVarsBreak, allowSynthBreak, allowArrayBreak, allowEnvirBreak, minPartitionSize); + columnBreakIndices = (possibleColumnBreakIndices.size <= (tryColumnNum - 1)).if { + possibleColumnBreakIndices; + }{ + (tryColumnNum == 1).if { [] }{ (varCtrNum + synthCtrNum).miSC_eqPart(possibleColumnBreakIndices, tryColumnNum) }; + }; + columnNum = (synthCtrNum + varCtrNum == 0).if { 0 }{ columnBreakIndices.size + 1 }; + + sliderWidth !? { maxSliderWidth = sliderWidth; minSliderWidth = sliderWidth; }; + effectiveSliderWidth = this.effectiveSliderWidth(columnNum, maxColumnNum, minSliderWidth, maxSliderWidth); + + colorsLo = colorsLo ?? { greyMode.if { greyModeColorsLoDefault }{ colorsLoDefault } }; + colorsHi = colorsHi ?? { greyMode.if { greyModeColorsHiDefault }{ colorsHiDefault } }; + + + ctrButtonGreyCenter = ctrButtonGreyCenter ?? { greyMode.if { greyModeCtrButtonGreyCenterDefault }{ ctrButtonGreyCenterDefault } }; + ctrButtonGreyDev = ctrButtonGreyDev ?? { + greyMode.if { greyModeCtrButtonGreyDevDefault }{ ctrButtonGreyDevDefault } + }; + + varColorNum = (this.varCtrColorPairs.collect(_[0]).maxItem ?? - 1) + 1; + synthColorNum = (this.synthCtrColorPairs.collect(_[0]).maxItem ?? - 1) + 1; + colorNum = varColorNum + synthColorNum + 2; + + totalWidth = effectiveSliderWidth * columnNum + ((columnNum - 1) * columnIndent) + leftMargin + rightMargin + 3 + 500; + + tempColors = colorNum.miSC_distinctColors(colorsLo, colorsHi, colorsLo, colorsHi, colorsLo, colorsHi, colorAreaUsage, greyMode); + + windowName = this.windowName(name, sliderPriority, playerPriority); + window = GUI.window.new(windowName, Rect(rrand(xPosMin, xPosMax), rrand(yPosMin, yPosMax), totalWidth, 80), resizable: false).front; + + window.onClose_({ + #window, playerSection, colors, varCtrColorPairs, varSliderDict, synthSliderDict, + synthCtrColorPairs, synthCtrSliders, varCtrSliders, synthNameBoxes = Array.newClear(10); + }); + + + cview = GUI.compositeView.new(window, Rect(0, 0, totalWidth, 80)); + cview.decorator = FlowLayout(cview.bounds, leftMargin @ upperMargin, gap @ gap); + + // build slider section + + sliderSectionHeight = this.placeSliders(sliderPriority, sliderType, cview, columnBreakIndices, + effectiveSliderWidth, sliderHeight, labelWidth, numberWidth, synthNumWidth, tempColors, numColorExp, + columnIndent, gap, leftMargin, varColorNum, synthColorNum, colorDeviation, greyMode, fontColor); + + heightK = (maxSliderFontHeight - minSliderFontHeight) / (maxFontSliderHeight - minFontSliderHeight); + sliderFontHeight = sliderFontHeight ?? case + { sliderHeight < minFontSliderHeight }{ minSliderFontHeight } + { sliderHeight > maxFontSliderHeight }{ maxSliderFontHeight } + { true } { (sliderHeight - minFontSliderHeight) * heightK + minSliderFontHeight }; + cview.decorator.reset; + cview.decorator.left_((effectiveSliderWidth + columnIndent) * columnNum + leftMargin); + cview.decorator.shift(y: gap); + + pviewBounds = Rect(0, 0, 450, 1000); + pview = CompositeView(cview, pviewBounds); + pview.decorator = FlowLayout(pviewBounds, 0 @ 0); + pview.background_(Color.new255(0, 150, 150, 0)); + + // build player section + + playerSection = try { VarGuiPlayerSection.new(this, pview, playerHeight, streamPlayerGroups, synthPlayerGroups, comboPlayerGroups, + ctrButtonGreyCenter, ctrButtonGreyDev, fontColor, playerPriority); + }{ + |error| + { window.close }.defer(0.5); + error.throw; + }; + + totalHeight = max(sliderSectionHeight, playerSection.totalHeight) + lowerMargin + upperMargin; + totalWidth = effectiveSliderWidth * columnNum + (columnNum * columnIndent) + playerSection.totalWidth + leftMargin + rightMargin + 3; + + cview.bounds = Rect(0, 0, totalWidth, totalHeight); + + cview.background = tempColors[colorNum - [1,2].choose]; + // if Gradient will be reimplemented in qt: + // Gradient(tempColors[colorNum - 1], tempColors[colorNum - 2], \v, colorSteps); + + window.bounds = Rect(rrand(xPosMin, xPosMax), rrand(yPosMin, yPosMax), totalWidth, totalHeight); + this.font(font, sliderFontHeight, playerFontHeight); + + [varCtrSliders, synthCtrSliders].do { |sliders| + sliders.do { |ez| + ez.miSC_adaptToControlStep(precisionSpan, stepEqualZeroDiv).miSC_mode_(sliderMode); + } + }; + + this.initSynthSliderDict; + this.initVarSliderDict; + + updateNow.if { this.update }; + ^this + } + + update { + varCtrSliders.do({|item| item.action.value(item) }); + synthCtrSliders.do({|item| item.action.value(item) }); + ^this + } + + font {|font = "Helvetica", sliderFontHeight = 16, playerFontHeight = 12| + var x; + varCtrSliders.do({|item| + item.labelView.font_(Font(font, sliderFontHeight)); + item.numberView.font_(Font(font, sliderFontHeight)); + }); + synthCtrSliders.do({|item| + item.labelView.font_(Font(font, sliderFontHeight)); + item.numberView.font_(Font(font, sliderFontHeight)); + }); + synthNameBoxes.do({|item| + item.font_(Font(font, sliderFontHeight)).refresh; + }); + + (x = playerSection.mouseActionButton) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + (x = playerSection.envirIndexButton) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + (x = playerSection.latencyButton) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + + playerSection.basicNewViews.do(_.font_(Font(font, playerFontHeight))); + (x = playerSection.modeNameView) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + + playerSection.streamEnvirViews.do(_.font_(Font(font, playerFontHeight))); + playerSection.streamTypeTexts.do(_.font_(Font(font, playerFontHeight))); + playerSection.synthRateTexts.do(_.font_(Font(font, playerFontHeight))); + + playerSection.optionViews.do(_.font_(Font(font, playerFontHeight))); + playerSection.optionViewTexts.do(_.font_(Font(font, playerFontHeight))); + + (x = playerSection.saveButton) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + (x = playerSection.updateButton) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + (x = playerSection.stopButton) !? { x.font_(Font(font, playerFontHeight)); x.refresh }; + + ^this + } + + + windowName {|name, sliderPriority, playerPriority| + var a,b; + ^(name ?? { + a = case + { (varCtrNum != 0) && (synthCtrNum != 0) } + { (sliderPriority == \var).if { "variable and synth control" }{ "synth and variable control" } } + { (varCtrNum == 0) && (synthCtrNum != 0) } { "synth control" } + { (varCtrNum != 0) && (synthCtrNum == 0) } { "variable control" } + { (varCtrNum == 0) && (synthCtrNum == 0) } { "no control" }; + b = case + { (streamPlayerNum != 0) && (synthPlayerNum != 0) } + { (playerPriority == \stream).if { "stream and synth players" }{ "synth and stream players" } } + { (streamPlayerNum == 0) && (synthPlayerNum != 0) } + { "synth player" ++ ((synthPlayerNum != 1).if { "s" }{ "" }) } + { (streamPlayerNum != 0) && (synthPlayerNum == 0) } + { "stream player" ++ ((streamPlayerNum != 1).if { "s" }{ "" }) } + { (streamPlayerNum == 0) && (synthPlayerNum == 0) } { "no players" }; + a ++ " | " ++ b; + }).asString; + } + + initVarCtrColorGroups { // logical variable control color grouping + var j = 0, col, k; + col = Array.newClear((varEnvirIndices.size != 0).if { + varEnvirIndices.maxItem + 1 + }{ + 0 + }); + + varCtr.do {|x,i| + i.odd.if { + k = varEnvirIndices[i.div(2)]; + x[0].isSequenceableCollection.if { + col[k] = col[k].add(x.collect {|y| j = j + 1; j - 1 }); + }{ + col[k] = col[k].add(j); + j = j + 1; + } + } + }; + // special case there could be nils if some synths without control + ^col.reject { |x| x.isNil } + } + + initSynthCtrColorGroups { // logical synth control color grouping + var j = 0, col, k; + + col = Array.newClear((synthCtrSynthIndices.size != 0).if { + synthCtrSynthIndices.maxItem + 1 + }{ + 0 + }); + + synthCtr.do {|x,i| + i.odd.if { + k = synthCtrSynthIndices[i.div(2)]; + x[0].isSequenceableCollection.if { + col[k] = col[k].add(x.collect {|y| j = j + 1; j - 1 }); + }{ + col[k] = col[k].add(j); + j = j + 1; + } + } + }; + // special case there could be nils if some synths without control + ^col.reject { |x| x.isNil } + } + + initSynthSliderDict { + var dict = MultiLevelIdentityDictionary.new; + var synthNum = this.synthCtrSynthIndices.asSet, relSynthCtrIndices, + sliderIndex = 0, key, size; + synthNum.do { |synthIndex| + relSynthCtrIndices = this.synthCtrSynthIndices.findAll([synthIndex]); + relSynthCtrIndices.do { |i| + key = synthCtr[i * 2]; + size = synthCtrSizes[i]; + dict.put(synthIndex, key, \size, size); + dict.put(synthIndex, key, \sliderIndex, sliderIndex); + sliderIndex = sliderIndex + size; + } + }; + this.synthSliderDict = dict; + } + + initVarSliderDict { + var dict = MultiLevelIdentityDictionary.new; + var sliderIndex = 0, size; + varCtr.pairsDo { |key, spec, i| + + size = varCtrSizes[i.div(2)]; + dict[key, \varOccurrences].isNil.if { + dict.put(key, \varNum, 0, \sliderIndex, sliderIndex); + dict.put(key, \varNum, 0, \size, size); + dict.put(key, \varOccurrences, 1); + }{ + dict.put(key, \varNum, dict[key, \varOccurrences], \sliderIndex, sliderIndex); + dict.put(key, \varNum, dict[key, \varOccurrences], \size, size); + dict.put(key, \varOccurrences, dict[key, \varOccurrences] + 1); + }; + sliderIndex = sliderIndex + size; + }; + this.varSliderDict = dict; + } +} + diff --git a/Classes/VarGui/VarGuiPlayerSection.sc b/Classes/VarGui/VarGuiPlayerSection.sc new file mode 100755 index 0000000..a045945 --- /dev/null +++ b/Classes/VarGui/VarGuiPlayerSection.sc @@ -0,0 +1,1193 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +VarGuiPlayerSection { + var <>varGui, <>streamPlayerGroups, <>synthPlayerGroups, <>comboPlayerGroups, synths, ctrButtonGreyCenter, <>ctrButtonGreyDev, <>playerPriority, placeSynthPlayers, placeStreamPlayers, + iconViewGroup, makeIconViewGroup, = 10).if { " e" }{ " e " } ++ + (varGui.streamEnvirIndices[i]).asString).background_(liteGreyBackgroundColor).stringColor_(fontColor); + + streamViewGroups[i] = Array.fill(3, { CompositeView(playerView, rectOut) }); + streamViewGroups[i].do(_.background = liteGreyBackgroundColor); + + streamPlayActions[i] = { |b| + ([-1,1,3].includes(streamStates[i])).if { + varGui.streams[i].play(varGui.clocks[i], quant: varGui.quants[i]); + } + }; + streamPauseActions[i] = { |b| + ([-1,0].includes(streamStates[i])).if { + varGui.streams[i].pause; + } + }; + streamResetActions[i] = { |b| + + varGui.streams[i].reset; + // reset type play + + (streamResetModeButtons[i].value == 0).if { + [-1,1,2,3].includes(streamStates[i]).if { + varGui.streams[i].play(varGui.clocks[i], quant: varGui.quants[i]); + }{ + { this.playerGuiAction(streamViewGroups[i], 2, \thisHi); }.defer; + { this.playerGuiAction(streamViewGroups[i], 2, \thisLo); }.defer(0.1); + }; + }{ // reset type pause + [0,1,2].includes(streamStates[i]).if { + + (streamStates[i] != 0).if { + streamStates[i] = 3; + { this.playerGuiAction(streamViewGroups[i], 1, \thisResetOtherLo); }.defer; + }{ + streamStates[i] = 3; + varGui.streams[i].pause; + }; + }; + }; + }; + + streamButtonGroups[i] = [ + Button(streamViewGroups[i][0], rectIn).states_([["", fontColor, playPlayerButtonColor]]) + .action_({ |b,mod| varGui.server.listSendBundle(latencies[latencyIndex], + this.dispatchCollect(mouseDownOn.not, mod, synthPlayActions, streamPlayActions, \stream, i)) }) + .mouseDownAction_({ |b,x,y,mod| varGui.server.listSendBundle(latencies[latencyIndex], + this.dispatchCollect(mouseDownOn, mod, synthPlayActions, streamPlayActions, \stream, i)) }), + Button(streamViewGroups[i][1], rectIn).states_([["", fontColor, pausePlayerButtonColor]]) + .action_({ |b,mod| varGui.server.listSendBundle(latencies[latencyIndex], + this.dispatchCollect(mouseDownOn.not, mod, synthPauseActions, streamPauseActions, \stream, i)) }) + .mouseDownAction_({ |b,x,y,mod| varGui.server.listSendBundle(latencies[latencyIndex], + this.dispatchCollect(mouseDownOn, mod, synthPauseActions, streamPauseActions, \stream, i)) }), + Button(streamViewGroups[i][2], rectIn).states_([["", fontColor, resetPlayerButtonColor]]) + .action_({ |b,mod| varGui.server.listSendBundle(latencies[latencyIndex], + this.dispatchCollect(mouseDownOn.not, mod, synthStopActions, streamResetActions, \stream, i, 1, true)) }) + .mouseDownAction_({ |b,x,y,mod| varGui.server.listSendBundle(latencies[latencyIndex], + this.dispatchCollect(mouseDownOn, mod, synthStopActions, streamResetActions, \stream, i, 1, true)) }), + ]; + + playerView.decorator.shift(x: columnGroupGap); + + streamResetModeViews[i] = CompositeView(playerView, modeRectOut); + + streamResetModeActions[i] = { |b| + b.value.switch( + 0, { streamResetModeViews[i].background = playBackgroundColor }, + 1, { streamResetModeViews[i].background = pauseBackgroundColor } + ); + }; + + { + var v = 0; + streamResetModeButtons[i] = + Button(streamResetModeViews[i], modeRectIn).states_([["", fontColor, modeButtonColor], ["", fontColor, modeButtonColor]]) + .action_({|b| this.dispatchPerform(streamResetModeButtons, modifier, streamResetModeActions, \streamReset, \stream, i); }) + // qt small button workaround + .mouseDownAction_({|b,x,y,m| modifier = m; v = 1-v; b.valueAction_(v) }); + }.(); + + [1,0].do {|x| streamResetModeButtons[i].valueAction_(x) }; + + playerView.decorator.shift(x: columnGroupGap + modeRectOut.width + decoratorGapX); + streamTypeTexts[i] = StaticText(playerView, smallRectOut).string_(varGui.streams[i].isKindOf(Task).if { "task" }{ "esp" }) + .background_(liteGreyBackgroundColor).stringColor_(fontColor).align_(\center); + + playerView.decorator.nextLine; + + streamSimpleControllers[i] = SimpleController(x).put(\userPlayed, {|n| + ([-1,1,2,3].includes(streamStates[i])).if { + { this.playerGuiAction(streamViewGroups[i], 0, \thisHiOtherLo); }.defer; + streamStates[i] = 0; + }; + }).put(\userStopped, {|n| + ([0,3].includes(streamStates[i])).if { + { + (streamStates[i] == 3).if { + this.playerGuiAction(streamViewGroups[i], 1, \thisResetOtherLo); + }{ + this.playerGuiAction(streamViewGroups[i], 1, \thisHiOtherLo); + }; + }.defer; + (streamStates[i] != 3).if { streamStates[i] = 1 } + }; + }).put(\stopped, {|n| + varGui.streams[i].streamHasEnded.if { + { this.playerGuiAction(streamViewGroups[i], 2, \thisStopOtherLo); }.defer; + streamStates[i] = 2; + }{ + (streamStates[i] != 3).if { streamStates[i] = 1 } + } + // e.g. ESP started by quant ... + }).put(\playing, {|n| + { this.playerGuiAction(streamViewGroups[i], 0, \thisHiOtherLo); }.defer; + streamStates[i] = 0; + }); + + + streamStates[i] = case // init EventStreamPlayer and Task states + { varGui.streams[i].streamHasEnded }{ { this.playerGuiAction(streamViewGroups[i], 2, \thisStopOtherLo); }.defer; 2 } + { varGui.streams[i].miSC_getIsWaiting } + { { this.playerGuiAction(streamViewGroups[i], 1, \thisPlayOtherLo); }.defer; 1 } + { varGui.streams[i].wasStopped } + { { this.playerGuiAction(streamViewGroups[i], 1, \thisHiOtherLo); }.defer; 1 } + { true }{ { this.playerGuiAction(streamViewGroups[i], 0, \thisHiOtherLo); }.defer; 0 }; + + }); + }; + + makeIconViewGroup = { + playerView.decorator.shift(x: basicNewRect.width + decoratorGapX); + iconViewGroup = Array.fill(3, { UserView(playerView, rectOut).background_(liteGreyBackgroundColor) }); + playerView.decorator.shift(x: columnGroupGap); + modeNameView = StaticText(playerView, modeNameRect).string_( + ((varGui.synthPlayerNum != 0) && (varGui.streamPlayerNum == 0) && (synthRenewModeStates.every(_==false))).if { + "no modes" // + }{ + "modes" + }).background_(liteGreyBackgroundColor).stringColor_(fontColor).align_(\center); + }; + + + (playerPriority == \synth).if { + placeSynthPlayers.(); + (varGui.synths.size != 0).if { + 1.do { playerView.decorator.nextLine }; + makeIconViewGroup.(); + 1.do { playerView.decorator.nextLine }; + + }; + (varGui.streams.size != 0).if { + (varGui.synths.size != 0).if { playerView.decorator.nextLine }; + placeStreamPlayers.(); + (varGui.synths.size == 0).if { + playerView.decorator.nextLine; + makeIconViewGroup.(); + }; + }; + }{ + placeStreamPlayers.(); + (varGui.streams.size != 0).if { + 1.do { playerView.decorator.nextLine }; + makeIconViewGroup.(); + 1.do { playerView.decorator.nextLine }; + }; + (varGui.synths.size != 0).if { + (varGui.streams.size != 0).if { playerView.decorator.nextLine }; + placeSynthPlayers.(); + (varGui.streams.size == 0).if { + playerView.decorator.nextLine; + makeIconViewGroup.(); + }; + }; + }; + + ((varGui.streamPlayerNum + varGui.synthPlayerNum) > 0).if { this.drawPlayers }; + + // cleanup + + stopByCmdPeriodActions.add({ { varGui.streams.do({|x,i| this.playerGuiAction(streamViewGroups[i], 1, \thisHiOtherLo); }) }.defer; }); + ((varGui.synthPlayerNum + varGui.streamPlayerNum) > 0).if { + stopByCmdPeriodActions.add({ + stopButton.doAction; + }) + }; + stopByCmdPeriodActions.do(CmdPeriod.add(_)); + + + playerView.onClose_({ + stopByCmdPeriodActions.do(CmdPeriod.remove(_)); + { + synthResponders.do({ |x| x.do { |y| y.disable; y.remove } }); + streamSimpleControllers.do(_.remove); + }.defer(0.2); + }); + + ((varGui.streamPlayerNum + varGui.synthPlayerNum) > 0).if { playerView.decorator.shift(y: optionViewsGapTop) }; + + // option section + + latencies = [0.1, varGui.server.latency, nil]; + latencyIndex = 0; + + optionViewMakers = [{ + mouseActionButton = Button(playerView, smallRectOut) + .states_([["on", fontColor, optionHiColor], ["off", fontColor, optionLoColor]]) + .action_({ |b| mouseDownOn = b.value.switch(0, { true }, 1, { false }) }).value_(1).valueAction_(0); + },{ + var v = 0; + envirIndexButton = Button(playerView, smallRectOut) + .states_([["on", fontColor, optionHiColor], ["off", fontColor, optionLoColor]]) + .action_({ |b| showEnvirIndex = b.value.switch( + 0, { varGui.refreshVarCtrSliderLabels(true); true }, + 1, { varGui.refreshVarCtrSliderLabels(false); false } + ) }) + .mouseDownAction_({ |b| v = 1 - v; b.valueAction_(v) }) // qt small button workaround + .value_((varGui.envirs.size > 1).if { 1 }{ 0 }).valueAction_((varGui.envirs.size > 1).if { 0 }{ 1 }); + },{ + var v = 1; + latencyButton = Button(playerView, smallRectOut) + .states_([["c", fontColor, optionHiColor], ["s", fontColor, optionHiColor], ["nil", fontColor, optionLoColor]]) + .action_({ |b| + b.value.switch( + 0, { latencyIndex = 0; + customLatencyBox.background_(optionHiColor); + serverLatencyBox.background_(optionLoColor); }, + 1, { latencyIndex = 1; + customLatencyBox.background_(optionLoColor); + serverLatencyBox.background_(optionHiColor); }, + 2, { latencyIndex = 2; + customLatencyBox.background_(optionLoColor); + serverLatencyBox.background_(optionLoColor); } + ) + }) + .mouseDownAction_({ |b| v = v + 1 % 3; b.valueAction_(v) }) // qt small button workaround + .value_(2); + },{ + customLatencyBox = NumberBox(playerView, smallRectOut).clipLo_(0.03).clipHi_(2).value_(0.1) + .background_(optionLoColor).stringColor_(fontColor).normalColor_(fontColor); + customLatencyBox.scroll_step = 0.01; + customLatencyBox.action_({|n| latencies[0] = n.value; }); + },{ + serverLatencyBox = NumberBox(playerView, smallRectOut).clipLo_(0.0).clipHi_(2) + .background_(optionLoColor) + .stringColor_(fontColor) + .normalColor_(fontColor) + .value_(serverLatency ?? { varGui.server.latency }); + serverLatencyBox.scroll_step = 0.01; + serverLatencyBox.action_({|n| varGui.server.latency = n.value; latencies[1] = n.value; }); + }]; + + 5.do {|i| + var str; + str = i.switch( + 0, { " player action by mouse down " }, + 1, { " show envir index in vars' name fields " }, + 2, { " bundle latency (synth players)" }, + 3, { " custom bundle latency" }, + 4, { " server latency (esplayer players)" } + ); + + (((i == 1) && (varGui.varCtrNum != 0)) || + ((i == 2) && (varGui.synthPlayerNum != 0)) || + ((i == 3) && (varGui.synthPlayerNum != 0)) || + ((i == 4) && (varGui.synthPlayerNum + varGui.streamPlayerNum != 0))).if { + optionViewTexts = optionViewTexts.add(StaticText(playerView, Rect(0, 0, optionViewWidth, fieldHeight)) + .string_(str).background_(liteGreyBackgroundColor).stringColor_(fontColor)); + playerView.decorator.shift(x: columnGroupGap); + optionViews = optionViews.add(optionViewMakers[i].()); + playerView.decorator.nextLine; + optionViewNum = optionViewNum + 1; + }; + }; + + totalHeight = totalHeight + optionViewsGapTop + (optionViewNum * fieldHeight) + + ((optionViewNum + 1) * decoratorGapX) + optionViewsGapBottom + globalButtonHeight; + + + playerView.decorator.shift(y: optionViewsGapBottom); + + globalButtonWidth = columnGroupGap + modeRectOut.width + decoratorGapX + 20; + globalButtonGap = (totalWidth - (3 * globalButtonWidth) - (2 * decoratorGapX)) / 2; + + ((varGui.synthCtrNum + varGui.varCtrNum) > 0).if { + updateButton = Button(playerView, globalButtonWidth @ globalButtonHeight); + updateButton.states = [["update", fontColor, updateButtonColor]]; + updateButton.action = { this.varGui.update }; + }{ + playerView.decorator.shift(globalButtonWidth + decoratorGapX) + }; + + playerView.decorator.shift(globalButtonGap); + + ((varGui.synthCtrNum + varGui.varCtrNum) > 0).if { + saveButton = Button(playerView, globalButtonWidth @ globalButtonHeight); + saveButton.states = [["save as", fontColor, saveButtonColor]]; + saveButton.action = { + Dialog.savePanel({ arg path; + File(path, "w").write(varGui.saveData.asCompileString).close; + },{ }) + } + }{ + playerView.decorator.shift(globalButtonWidth + decoratorGapX) + }; + + playerView.decorator.shift(globalButtonGap); + + ((varGui.synthPlayerNum + varGui.streamPlayerNum) > 0).if { + stopButton = Button(playerView, globalButtonWidth @ globalButtonHeight); + stopButton.states = [["stop", fontColor, stopButtonColor]]; + stopButton.action = { + varGui.streams.do {|item| /*item.free;*/ item.stop; }; + varGui.synthIDs.do {|item, i| + synthActionStates[i] = 3; + + parentHelpSynths[i].isNil.if { + (synthStates[i] != 2).if { + (synthStates[i] == -1).if { + // basic new + this.updateSynth(i); + varGui.server.listSendBundle(nil, [synths[i].newMsg, synths[i].miSC_freeMsg]); + }{ + varGui.server.sendMsg("/n_free", item.asNodeID); + } + } + }{ + // synth derived from HS + synths[i].isPlaying.if { varGui.server.sendBundle(nil, synths[i].miSC_runMsg(false)) } + } + } + } + }; + ^this + } + + playerGuiAction {|viewGroup, j, type| + type.switch( + \allLo, { 3.do({|x| (viewGroup[x]).background = buttonLoColor}); }, + \thisHiOtherLo, { viewGroup[j].background = buttonHiColor; + Set[0,1,2].remove(j).do({|x| (viewGroup[x]).background = buttonLoColor}); }, + \thisResetOtherLo, { viewGroup[j].background = resetBackgroundColor; + Set[0,1,2].remove(j).do({|x| (viewGroup[x]).background = buttonLoColor}); }, + \thisPlayOtherLo, { viewGroup[j].background = playBackgroundColor; + Set[0,1,2].remove(j).do({|x| (viewGroup[x]).background = buttonLoColor}); }, + \thisHi, { viewGroup[j].background = buttonHiColor; }, + \thisLo, { viewGroup[j].background = buttonLoColor; }, + \thisStopOtherLo, { viewGroup[j].background = stopBackgroundColor; + Set[0,1,2].remove(j).do({|x| (viewGroup[x]).background = buttonLoColor}); } + ); + ^this + } + + + dispatchPerform { |buttons, mod, actions, mode, reg, i| + var num, group, isInSameGroup, isOfSameState; + (mod.isInteger and: { mod.isShift }).if { + num = actions.size; + group = ((reg == \synth).if { synthPlayerGroups }{ streamPlayerGroups }).detect(_.includes(i)); + num.collect { |j| + isInSameGroup = group.includes(i); + ((mod.isAlt && isInSameGroup) || (mod.isAlt.not)).if { + ((mode == \synthRenew) && // exclude cases when renew mode button greyed by stop mode + ((synthStopModeButtons[j].value == 0) || + ((synthStopModeButtons[j].value != 0) && (synthStopModeButtons[i].value == 0)) + ) + ).not.if { + // no action if synth from HS + ((reg == \stream) or: { parentHelpSynths[j].isNil }).if { + (j != i).if { buttons[j].value = buttons[i].value; }; + actions[j].(buttons[i], mod); + } + }{ + (j == i).if { buttons[j].value = buttons[j].value - 1 % 3; }; + }; + }; + }; + + }{ + actions[i].(buttons[i], mod); + }; + ^this + } + + dispatchCollect { |doIt, mod, synthActions, streamActions, reg, i, flattenNum = 1, stopButtonAction = false| + var num, group, actions, isInSameGroup, isOfSameState, synthState, comboOffset, firstActions, secondActions, + synthStopModeState, synthRenewModeState, streamState, streamResetModeState; + + ^doIt.if { + actions = (reg == \synth).if { synthActions }{ streamActions }; + (mod.isInteger and: { mod.isShift }).if { + (mod.miSC_isPseudoCaps).if { + comboOffset = (reg == \synth).if { + (playerPriority == \synth).if { 0 }{ varGui.streamPlayerNum }; + }{ + (playerPriority == \synth).if { varGui.synthPlayerNum }{ 0 } + }; + (playerPriority == \synth).if { + firstActions = synthActions; + secondActions = streamActions; + }{ + firstActions = streamActions; + secondActions = synthActions; + }; + + ((mod.isAlt).if { comboPlayerGroups.detect(_.includes(i + comboOffset)) } { synthActions.size + streamActions.size }) + .collect { |j| + // don't stop synth from HS indirectly with shift + caps + (j >= firstActions.size).if { + (((playerPriority == \synth) || stopButtonAction.not) or: + { parentHelpSynths[j - firstActions.size].isNil }).if { + secondActions[j - firstActions.size].(); + } + }{ + (((playerPriority == \stream) || stopButtonAction.not) or: { parentHelpSynths[j].isNil }).if { + firstActions[j].(); + } + } + }.flatten(flattenNum); + }{ + num = actions.size; + group = ((reg == \synth).if { synthPlayerGroups }{ streamPlayerGroups }).detect(_.includes(i)); + + synthState = synthStates[i]; + synthStopModeState = synthStopModeButtons[i].(); + synthRenewModeState = synthRenewModeButtons[i].(); + streamState = streamStates[i]; + streamResetModeState = streamResetModeButtons[i].(); + + num.collect { |j| + isInSameGroup = group.includes(j); + + isOfSameState = (reg == \synth).if { + ((synthStates[j] == synthState) && + (((synthStopModeState == 0) && (synthStopModeButtons[j].() == 0)) || + ((synthStopModeState == synthStopModeButtons[j].()) && + (synthRenewModeState == synthRenewModeButtons[j].())))) + }{ + ((streamStates[j] == streamState) && (streamResetModeButtons[j].() == streamResetModeState)) + }; + // don't stop synth from HS indirectly with shift + // lookup parentHelpSynths only if reg = \synth + ( ((reg == \stream) || stopButtonAction.not) or: { parentHelpSynths[j].isNil } ).if { + case + { mod.isCtrl && mod.isAlt } + { (isInSameGroup && isOfSameState).if { actions[j].(); } } + { mod.isCtrl } + { isOfSameState.if { actions[j].(); } } + { mod.isAlt } + { isInSameGroup.if { actions[j].(); } } + { true } + { actions[j].(); } + }; + }.flatten(flattenNum); + } + }{ + actions[i].(); + }; + }; + } + +} + + diff --git a/Classes/VarGui/extBoolean.sc b/Classes/VarGui/extBoolean.sc new file mode 100644 index 0000000..1549532 --- /dev/null +++ b/Classes/VarGui/extBoolean.sc @@ -0,0 +1,43 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + ++Boolean { + + miSC_dispatchCollect { |doGrouping, funcs, i, groups, flattenNum = 1| + var groupIndex; + ^this.if { + doGrouping.if { + groupIndex = groups.detectIndex { |g| g.includes(i) }; + (groups[groupIndex] + .collect { |j| funcs[j].value }).flatten(flattenNum); + }{ + funcs[i].value; + }; + }; + } +} + + diff --git a/Classes/VarGui/extCollection.sc b/Classes/VarGui/extCollection.sc new file mode 100644 index 0000000..c1f3b6b --- /dev/null +++ b/Classes/VarGui/extCollection.sc @@ -0,0 +1,49 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + ++Collection { + + miSC_enumerateIndices { + (this.size == 1).if { + ^(0..(this[0]-1)); + }{ + ^[(0..(this[0]-1)), this.copyToEnd(1).miSC_enumerateIndices] + .allTuples.collect(_.flatten) + } + } + + miSC_isGrouping {|n| + var f; + this.every({|x| x.isKindOf(Collection) and: { x.every({|y| y.isInteger})} }).not.if { ^false }; + f = this.asSequenceableCollection.collect(_.asSequenceableCollection).flatten; + ((f.size == n) and: { f.every({|x| (x>=0) && (x= 0 and <= 1, deviation > 0 and <= 1 + var a = deviation.linlin(0, 1, greyCenter!3, [this.red, this.green, this.blue]) ++ [this.alpha]; + ^Color(*a); + } + + miSC_dim { |ctrButtonGreyCenter, ctrButtonGreyDev| + ^this.miSC_iplToGrey(ctrButtonGreyCenter, ctrButtonGreyDev) + } + +} + + diff --git a/Classes/VarGui/extControlSpec.sc b/Classes/VarGui/extControlSpec.sc new file mode 100644 index 0000000..c4eb5ae --- /dev/null +++ b/Classes/VarGui/extControlSpec.sc @@ -0,0 +1,39 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++ ControlSpec { + + // redundant naming as method also applied to Symbols refering to specs + miSC_specAsArray { |synthName, metaKey = \specs, useGlobalSpecs = true| + var s, i, typeString, indices; + s = this.asCompileString; + i = s.findAll("'"); + typeString = s[(i[0]+1)..(i[1]-1)]; + ^[this.minval, this.maxval, typeString.asSymbol, this.step, this.default] + } +} + + + diff --git a/Classes/VarGui/extDictionary.sc b/Classes/VarGui/extDictionary.sc new file mode 100644 index 0000000..1d2a974 --- /dev/null +++ b/Classes/VarGui/extDictionary.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Dictionary { + miSC_maybePutPairs { arg ...args; + args.pairsDo { |key, val| this.at(key).isNil.if { this.put(key, val) } }; + ^this + } +} diff --git a/Classes/VarGui/extEZSlider.sc b/Classes/VarGui/extEZSlider.sc new file mode 100644 index 0000000..842f05c --- /dev/null +++ b/Classes/VarGui/extEZSlider.sc @@ -0,0 +1,84 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++EZSlider { + + miSC_colorize { |color, numColorExp = 0.4, fontColor| + var light = color.miSC_exp(numColorExp), backGroundColor; + backGroundColor = (\EZSmoothSlider.asClass.notNil and: + { this.isMemberOf(EZSmoothSlider) }).if { + this.sliderView.hiliteColor_(color); + light + }{ + color + }; + this.setColors(stringBackground: light, sliderBackground: backGroundColor, + numBackground: light, stringColor: fontColor, + numStringColor: fontColor, numNormalColor: fontColor); + ^this + } + + // number of indicated digits derived from controlSpec step + + miSC_adaptToControlStep { |precision = 10, stepEqualZeroDiv = 100| + var x, stepString, range, estimatedControlStep; + + estimatedControlStep = (controlSpec.step.abs < (10 ** precision.neg)).if { + (controlSpec.clipHi - controlSpec.clipLo) / stepEqualZeroDiv + }{ + controlSpec.step + }; + stepString = estimatedControlStep.miSC_decimalStrings(precision); + this.round = 10 ** stepString.last.size.neg; + range = controlSpec.constrain(controlSpec.clipHi) - + controlSpec.constrain(controlSpec.clipLo); + + (range < (10 ** precision.neg)).if { + // dummy controlspec should look inactive everywhere + this.sliderView.enabled = false; + this.numberView.enabled = false; + this.isMemberOf(EZSlider).if { + this.sliderView.thumbSize = 0; + } + }{ + sliderView.step = 1 / (range / estimatedControlStep).round; + }; + this.isMemberOf(EZSlider).if { + numberView.maxDecimals = stepString.last.size + }; + // take modifiers for multiple slider handling + sliderView.alt_scale_(1); + sliderView.ctrl_scale_(1); + sliderView.shift_scale_(1); + numberView.alt_scale_(1); + numberView.ctrl_scale_(1); + numberView.shift_scale_(1); + ^this + } + + miSC_mode_ { |type| + // subclasses EZSmoothSlider, EZRoundSlider may not be defined + // so distinguish here ... + ^this.isMemberOf(EZSlider).if { this }{ this.sliderView.perform(\mode_, type); this } } +} diff --git a/Classes/VarGui/extFloat.sc b/Classes/VarGui/extFloat.sc new file mode 100644 index 0000000..59c67fb --- /dev/null +++ b/Classes/VarGui/extFloat.sc @@ -0,0 +1,77 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + ++Float { + miSC_decimalStrings { |precision = 8| + var precString = this.asStringPrec(precision), prePointString, postPointString, + signString, manString, expString, posOfPoint, shift; + + #manString, expString = precString.split($e); + (manString[0] == $-).if { + manString = manString.drop(1); + signString = "-"; + }; + + expString.isNil.if { + // no exponent + posOfPoint = precString.find("."); + posOfPoint.isNil.if { + prePointString = precString; + }{ + prePointString = precString.copyFromStart(posOfPoint-1); + postPointString = precString.copyToEnd(posOfPoint+1); + } + }{ + // with exponent + shift = expString.drop(1).asInteger; + (expString[0] == $+).if { + (manString.size == 1).if { + // no comma + prePointString = manString ++ ($0!shift).join; + }{ + (shift < (manString.size-2)).if { + prePointString = manString[0].asString ++ manString.copyRange(2, shift+1); + postPointString = manString.copyToEnd(shift+1); + }{ + prePointString = manString[0].asString ++ manString.copyToEnd(2) ++ + ($0 ! (shift - (manString.size-2))).join; } + } + }{ + prePointString = "0"; + (manString.size == 1).if { + // no comma + postPointString = ($0!(shift-1)).join ++ manString; + }{ + postPointString = ($0!(shift-1)).join ++ + manString[0].asString ++ manString.copyToEnd(2); + } + } + }; + ^[signString, prePointString, postPointString] + } + +} + diff --git a/Classes/VarGui/extFunction.sc b/Classes/VarGui/extFunction.sc new file mode 100644 index 0000000..31d6611 --- /dev/null +++ b/Classes/VarGui/extFunction.sc @@ -0,0 +1,34 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ Function { + + // workaround for backwards compatibility + + miSC_performWithEnvir { |selector, envir| + if(selector === \value) { ^this.valueWithEnvir(envir) }; + ^super.miSC_performWithEnvir(selector, envir) + } + +} diff --git a/Classes/VarGui/extFunctionDef.sc b/Classes/VarGui/extFunctionDef.sc new file mode 100644 index 0000000..780512b --- /dev/null +++ b/Classes/VarGui/extFunctionDef.sc @@ -0,0 +1,34 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ FunctionDef { + + // workaround for backwards compatibility + + miSC_makeEnvirFromArgs { + var argNames, argVals; + argNames = this.argNames; + argVals = this.prototypeFrame.keep(argNames.size); ^().putPairs([argNames, argVals].flop.flatten) + } +} diff --git a/Classes/VarGui/extInteger_1.sc b/Classes/VarGui/extInteger_1.sc new file mode 100644 index 0000000..8e6f758 --- /dev/null +++ b/Classes/VarGui/extInteger_1.sc @@ -0,0 +1,114 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Integer { + + miSC_groupIndices {|groups| + var i = groups.size; + ^(this.collect({|j| + groups.detectIndex({ |item, k| item.includes(j) }) ?? { i = i + 1; i - 1 }; + })) + } + + miSC_cubeDivision {|dim| // division of unit cube fine enough for given number + var divCeiling = (this ** dim.reciprocal).ceil.asInteger, + div, prod, prod2, i = 0; + div = divCeiling ! dim; + prod = div.product; + prod2 = prod * (div[0] - 1) / div[0]; + while ({ + (i <= (dim-1)) && (prod >= this) && (prod2 >= this) + },{ + div[i] = div[i] - 1; + i = i + 1; + prod = prod2; + prod2 = prod * (div[i] - 1) / div[i]; + }); + ^div; + } + + miSC_selectCubeComponent {|index, areaUsage| + var lo, mid, hi; + mid = (index + 0.5) / this; + ^rrand(mid - (areaUsage / this / 2), mid + (areaUsage / this / 2)); + } + + miSC_distinctCubePoints {|dim, areaUsage = 0.9| // just for handsome integers ! + var div = this.miSC_cubeDivision(dim); + ^div.miSC_enumerateIndices.scramble.copyFromStart(this - 1) + .collect { |x| + x.collect { |y,i| + div[i].miSC_selectCubeComponent(y, areaUsage) + }; + }; + } + + miSC_distinctColors {|redLo = 0.4, redHi = 0.7, greenLo = 0.4, greenHi = 0.7, + blueLo = 0.4, blueHi = 0.7, areaUsage = 0.9, greyMode = false| // just for handsome integers ! + var cubePoints = greyMode.if { (0..this-1).scramble / (this - 1) }{ this.miSC_distinctCubePoints(3, areaUsage) }; + + ^this.collect {|i| + Color(greyMode.if { cubePoints[i] }{ cubePoints[i][0] } * (redHi - redLo) + redLo, + greyMode.if { cubePoints[i] }{ cubePoints[i][1] } * (greenHi - greenLo) + greenLo, + greyMode.if { cubePoints[i] }{ cubePoints[i][2] } * (blueHi - blueLo) + blueLo); + } + } + + + miSC_colorDeviationPairs {|colorGroups| + // expects double nested collection with all indices occuring + // outer groups mean related colors, inner groups same color + var pairs = Array.newClear(this), n; + colorGroups.do {|group,i| + n = group.size; + group.do {|item, j| + item.isNumber.if { + pairs[item] = [i, n - j - 1]; }{ + item.do {|jtem| pairs[jtem] = [i, n - j - 1] }; + }; + }; + }; + ^pairs; + } + + miSC_getCtrIndex { |argName| ^nil } + + + miSC_runMsg { arg flag = true; + ^[12, this, flag.binaryValue]; + } + + miSC_setMsg { arg ... args; + ^[15, this] ++ args.asOSCArgArray; + } + + miSC_setnMsg { arg ... args; + ^[16, this] ++ Node.setnMsgArgs(*args); + } + + miSC_freeMsg { ^[11, this] } + + +} diff --git a/Classes/VarGui/extInteger_2.sc b/Classes/VarGui/extInteger_2.sc new file mode 100644 index 0000000..1b7f7d8 --- /dev/null +++ b/Classes/VarGui/extInteger_2.sc @@ -0,0 +1,97 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Integer { + + + miSC_partMax { |part| + ^(part.size + 1).collect {|i| + case + { i == 0 }{ part[i] } + { i == part.size }{ this - part[i - 1] } + { true }{ part[i] - part[i - 1] } + }.maxItem; + } + + + miSC_eqPart { |part, k| + // search for quite equal partitions, needed for column break + // part expects ordered list that describes a partition of the integer by indices (ascending numbers > 0, < given integer) + // gives a new partition with k indices + var eqPart, subPart, eqSubPart, newEqSubPart, min, newMin, div, l, m, r, deltaLo, deltaHi, eqIndex; + case + { k == (part.size + 1) } + { eqPart = part } + { k > (part.size + 1) } + { Error("no possible partition").throw; } + { k == 2 } + { + m = part.size; + r = part.detectIndex(_ >= (this/2)); + case + { r.isNil } + { eqPart = [part[m-1]] } + { r == 0 } + { eqPart = [part[0]] } + { true }{ + deltaLo = (this/2) - part[r - 1]; + deltaHi = part[r] - (this/2); + eqPart = (deltaLo >= deltaHi).if { [part[r]] }{ [part[r - 1]] }; + } + } + { true } + { + // search around k-th part, then go on recursively + + l = 0; + div = this/k; + while { + (r.isNil) && (l < (part.size - k)) + }{ + (part[l] >= div).if { r = l }; + l = l + 1; + }; + + ((r.isNil) || (r == 0)).if { + eqIndex = ((r.isNil).if { part.size - k }{ 0 }); + subPart = part.drop(eqIndex + 1) - part[eqIndex]; + eqSubPart = (this - part[eqIndex]).miSC_eqPart(subPart, k - 1); + }{ + [r - 1, r].do {|i,j| + subPart = part.drop(i+1) - part[i]; + newEqSubPart = (this - part[i]).miSC_eqPart(subPart, k - 1); + newMin = max(part[i], (this - part[i]).miSC_partMax(newEqSubPart)); + ((j == 0) or: { newMin < min }).if { + min = newMin; + eqIndex = i; + eqSubPart = newEqSubPart; + }; + }; + }; + eqPart = [part[eqIndex]] ++ (eqSubPart + part[eqIndex]); }; + ^eqPart + } + + +} diff --git a/Classes/VarGui/extInteger_3.sc b/Classes/VarGui/extInteger_3.sc new file mode 100644 index 0000000..0624bbc --- /dev/null +++ b/Classes/VarGui/extInteger_3.sc @@ -0,0 +1,51 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++Integer { + miSC_isPseudoCaps { ^this.isCmd } + + miSC_checkColorGroups { |colorGrouping| + var flattenedColl, bool = false; + colorGrouping.isSequenceableCollection.not.if { + SimpleInputError("varColorGroups / synthColorGroups must be SequenceableCollection").throw + }; + colorGrouping.every { |x| x.isSequenceableCollection.not }.if { + SimpleInputError("varColorGroups / synthColorGroups must be grouping").throw + }; + + flattenedColl = colorGrouping.flatten(1); + flattenedColl.any { |x| x.isSequenceableCollection.not }.if { + (flattenedColl.every { |x| x.isInteger and: { x < this } } and: + { flattenedColl.asSet.size == this }).if { + bool = true; + }; + }; + bool.not.if { + SimpleInitError("varColorGroups / synthColorGroups must be correct grouping of number " ++ + this.asString ++ ". E.g. [[2], [0,3], [1,4]] is a valid grouping of 5. You can use method " ++ + "clumps, e.g. (0..4).clumps([1,3,2]).").throw + }; + } +} diff --git a/Classes/VarGui/extNil.sc b/Classes/VarGui/extNil.sc new file mode 100644 index 0000000..70fe9b2 --- /dev/null +++ b/Classes/VarGui/extNil.sc @@ -0,0 +1,27 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Nil { + miSC_asSet { ^Set[] } +} diff --git a/Classes/VarGui/extNode.sc b/Classes/VarGui/extNode.sc new file mode 100644 index 0000000..d29446e --- /dev/null +++ b/Classes/VarGui/extNode.sc @@ -0,0 +1,45 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +// doubling, keep extension for Integer private + ++Node { + + miSC_runMsg { arg flag=true; + ^[12, nodeID,flag.binaryValue]; + } + + miSC_setMsg { arg ... args; + ^[15, nodeID] ++ args.asOSCArgArray; + } + + miSC_setnMsg { arg ... args; + ^[16, nodeID] ++ Node.setnMsgArgs(*args); + } + + miSC_freeMsg { ^[11, nodeID] } + +} + + diff --git a/Classes/VarGui/extObject.sc b/Classes/VarGui/extObject.sc new file mode 100644 index 0000000..1fe516b --- /dev/null +++ b/Classes/VarGui/extObject.sc @@ -0,0 +1,48 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Object { + + miSC_isGrouping { ^false } + + miSC_getCtrIndex { |argName| ^nil } + + miSC_collectCopy { ^this } + + // workaround for backwards compatibility + + miSC_performWithEnvir { |selector, envir| + var argNames, args; + var method = this.class.findRespondingMethodFor(selector); + if(method.isNil) { ^this.doesNotUnderstand(selector) }; + + envir = method.miSC_makeEnvirFromArgs.putAll(envir); + argNames = method.argNames.drop(1); + args = envir.atAll(argNames); + ^this.performList(selector, args) + } + + miSC_defNameAsArray { ^this.asArray } + +} diff --git a/Classes/VarGui/extOther.sc b/Classes/VarGui/extOther.sc new file mode 100644 index 0000000..fbd5ae2 --- /dev/null +++ b/Classes/VarGui/extOther.sc @@ -0,0 +1,57 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// nonprivate, no prefix "miSC_" + ++SequenceableCollection { + + // actually could be named pairsDup + + specPairsDup { |num| + ^this.clump(2).collect(_!num).flatten(2) + } + + specPairsDupGroups { |num| + ^(0..(this.size.div(2) * num - 1)).clump(num).flop + } +} + + ++Event { + asESP { } +} + ++EventStreamPlayer { + asESP { ^this } +} + ++Stream { + asESP { |protoEvent| ^this.asEventStreamPlayer(protoEvent) } +} + ++Pattern { + asESP { |protoEvent| ^this.asEventStreamPlayer(protoEvent) } +} + diff --git a/Classes/VarGui/extPauseStream.sc b/Classes/VarGui/extPauseStream.sc new file mode 100644 index 0000000..9b8b22e --- /dev/null +++ b/Classes/VarGui/extPauseStream.sc @@ -0,0 +1,32 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++PauseStream { + + miSC_getIsWaiting { + ^isWaiting + } + +} diff --git a/Classes/VarGui/extSequenceableCollection_1.sc b/Classes/VarGui/extSequenceableCollection_1.sc new file mode 100644 index 0000000..6422c02 --- /dev/null +++ b/Classes/VarGui/extSequenceableCollection_1.sc @@ -0,0 +1,58 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++SequenceableCollection { + + miSC_isGrouping { |n| + var f; + this.every { |x| + x.isKindOf(Collection) and: { x.every {|y| y.isInteger} } + }.not.if { ^false }; + f = this.collect(_.asSequenceableCollection).flatten.asSet; + ((f.size == n) and: { f.every {|x| (x >= 0) && (x < n) } }).not.if { ^false }; + ^true + } + + miSC_isConnected { + // expects grouping + var y; + this.every { |x| + y = x.sort; + (y.size > 0).if { + (y.last - y.first + 1) == y.size + }{ + true + } + }.if { ^true }{ ^false }; + } + + miSC_groupingFromIndices { + var max = this.maxItem, groups; + groups = Array.newClear(max + 1); + this.do { |x,i| groups[x] = groups[x].add(i) }; + ^groups + } + + +} diff --git a/Classes/VarGui/extSequenceableCollection_2.sc b/Classes/VarGui/extSequenceableCollection_2.sc new file mode 100644 index 0000000..37ff2c7 --- /dev/null +++ b/Classes/VarGui/extSequenceableCollection_2.sc @@ -0,0 +1,200 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++SequenceableCollection { + + miSC_pfuncPbindsFromTuples { | pBefore, pReplace, pAfter, instrument, + excludeDur = false, excludeLegato = false, post = false, trace = false | + + // method for a SequenceableCollection of tuples [symbol, n], + // where n > 1 indicates an arrayed arg + + // miSC_pfuncPbindsFromTuples and miSC_sVarGuiSpecsFromTuples exist + // to avoid multiple lookups in SynthDef metadata by pVarGui + + + var pat, keyPfuncPairs = List.new, replaceIndex; + this.do { |keyNumPair| + keyPfuncPairs.add(keyNumPair[0]).add(Pfunc { + var key, num, val; + #key, num = keyNumPair; + val = currentEnvironment[key]; + (num > 1).if { [val] }{ val } + }) + }; + keyPfuncPairs = pBefore.asArray ++ + (instrument !? [\instrument, instrument]).asArray ++ + excludeDur.if { [] }{ [\dur, Pfunc { ~dur }] } ++ + excludeLegato.if { [] }{ [\legato, Pfunc { ~legato }] } ++ + keyPfuncPairs ++ pAfter.asArray; + + pReplace.pairsDo { |key, pat| + replaceIndex = keyPfuncPairs.indexOf(key); + replaceIndex.notNil.if { keyPfuncPairs[replaceIndex + 1] = pat } + }; + post.if { + ["", "Pbind pairs:", ""].do(_.postln); + keyPfuncPairs.pairsDo { |key, pat| + Char.tab.post; + key.post; + Char.tab.post; + pat.postln; + }; + "".postln; + }; + pat = Pbind(*keyPfuncPairs); + ^trace.if { pat.trace }{ pat } + } + + + miSC_specAsArray { |synthName, metaKey = \specs, useGlobalSpecs = true| + this.every { |x| x.isKindOf(Symbol) || x.isKindOf(String) }.if { + ^this.collect(_.miSC_specAsArray(synthName, metaKey, useGlobalSpecs)) + }{ + ^this.copy + } + } + + miSC_oddSpecAsArray { |synthName, metaKey = \specs, useGlobalSpecs = true| + var c = Array.newClear(this.size); + ^c.do { |item, i| + i.odd.if { + c[i] = this[i].miSC_specAsArray.copy + }{ + c[i] = this[i] + } + } + } + + miSC_sVarGuiData { | ...args | + var sVarGuiArgs = [\ctrBefore, \ctrReplace, \ctrAfter, \exclude, \metaKey, \useGlobalSpecs, \num], + synthCtr = [], synth = [], server, input; + + this.every { |x| (x.isKindOf(Symbol) || x.isKindOf(String)) }.not.if { + SimpleInitError("Items of SequenceableCollection as receiver of method " ++ + "sVarGui must be Symbol or String").class_(VarGui).throw + }; + input = this.collect(_.asSymbol); + + // last arg may be Server + + args.last.isKindOf(Server).if { + server = args.last; + args = args.drop(-1); + }; + (args == []).if { args = ()!(this.size) }; + + // this doesn't check args itself but only its arrangement as collection of dictionaries + + (((args.size == 0) || (args.size == this.size)) && args.every { |x| + x.isKindOf(Dictionary) and: { x.keys.isSubsetOf(sVarGuiArgs) } }).not.if { + SimpleInitError("Args of method aSequenceableCollection.sVarGui must be Dictionaries." ++ + " Their keys must be valid arg names of aSymbol.sVarGui: ctrBefore, ctrReplace, " ++ + "ctrAfter, exclude, metaKey, useGlobalSpecs, num.").class_(VarGui).throw + }; + + args.do { |dict, i| + dict = dict.copy; + dict.miSC_maybePutPairs(\metaKey, \specs, \useGlobalSpecs, true, \num, 1); + + synthCtr = synthCtr ++ (input[i].miSC_performWithEnvir(\sVarGuiSpecs, dict)); + synth = synth ++ (input[i] ! (dict[\num] ?? { 1 })); + + }; + ^[synthCtr, synth, server]; + } + + sVarGui { | ...args | + var data = this.miSC_sVarGuiData(*args); + ^VarGui(synthCtr: data[0], synth: data[1], server: data[2]); + } + + miSC_pVarGuiData { | ...args | + var pVarGuiArgs = [\ctrBefore, \ctrReplace, \ctrAfter, \durCtr, \legatoCtr, + \pBefore, \pReplace, \pAfter, \exclude, \excludeGate, \clock, \quant, + \metaKey, \useGlobalSpecs, \post, \trace, \num], data, + varCtr = [], stream = [], clock = [], quant = [], input; + + // this doesn't check args itself but only its arrangement as collection of dictionaries + + this.every { |x| (x.isKindOf(Symbol) || x.isKindOf(String)) }.not.if { + SimpleInitError("Items of SequenceableCollection as receiver of method " ++ + "pVarGui must be Symbol or String").class_(VarGui).throw + }; + input = this.collect(_.asSymbol); + + (args == []).if { args = ()!(this.size) }; + + (((args.size == 0) || (args.size == this.size)) && args.every { |x| + x.isKindOf(Dictionary) and: { x.keys.isSubsetOf(pVarGuiArgs) } }).not.if { + SimpleInitError("Args of method aSequenceableCollection.pVarGui must be Dictionaries." ++ + " Their keys must be valid arg names of aSymbol.sVarGui: ctrBefore, ctrReplace, ctrAfter, " ++ + "durCtr, legatoCtr, pBefore, pReplace, pAfter, exclude, excludeGate, " ++ + "clock, quant, metaKey, useGlobalSpecs, post, trace, num.").class_(VarGui).throw + }; + + args.do { |dict, i| + dict = dict.copy; + dict.miSC_maybePutPairs(\durCtr, #[0.05, 3, \exp, 0, 0.2], \legatoCtr, #[0.1, 5, \exp, 0, 0.8], + \excludeGate, true, \metaKey, \specs, \useGlobalSpecs, true, \post, false, \trace, false, \num, 1); + + data = input[i].miSC_performWithEnvir(\miSC_pVarGuiData, dict); + varCtr = varCtr ++ data[0]; + stream = stream ++ data[1]; + clock = clock ++ data[2]; + quant = quant ++ data[3]; + }; + ^[varCtr, stream, clock, quant]; + } + + pVarGui { | ...args | + var data = this.miSC_pVarGuiData(*args); + ^VarGui(data[0], stream: data[1], clock: data[2], quant: data[3]) + } + + psVarGui { | pVarGuiArgDictionaries, sVarGuiArgDictionaries, server | + var streamVarGuiData, synthVarGuiData, src, pDicts, sDicts, wrapper; + src = this.collect(_.miSC_defNameAsArray); + wrapper = { |x| x.isKindOf(Dictionary).if { [x] }{ x.asArray } }; + pDicts = wrapper.(pVarGuiArgDictionaries); + sDicts = wrapper.(sVarGuiArgDictionaries); + + ((src.size == 2) && src.every { |x| x.every { |y| y.isKindOf(Symbol) || y.isKindOf(String) } }).not.if { + SimpleInitError("Receiver of method psVarGui / spVarGui must be SequenceableCollection of " ++ + "two items that may be Symbols / Strings or SequenceableCollections thereof").class_(VarGui).throw + }; + + streamVarGuiData = src[0].miSC_pVarGuiData(*pDicts); + synthVarGuiData = src[1].miSC_sVarGuiData(*sDicts); + + ^VarGui(streamVarGuiData[0], synthVarGuiData[0], streamVarGuiData[1], synthVarGuiData[1], + clock: streamVarGuiData[2], quant: streamVarGuiData[3], server: server) + } + + spVarGui { | sVarGuiArgDictionaries, pVarGuiArgDictionaries, server | + ^this.reverse.psVarGui(pVarGuiArgDictionaries, sVarGuiArgDictionaries, server); + } + +} + diff --git a/Classes/VarGui/extSimpleNumber.sc b/Classes/VarGui/extSimpleNumber.sc new file mode 100644 index 0000000..640e5ad --- /dev/null +++ b/Classes/VarGui/extSimpleNumber.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ SimpleNumber { + miSC_specAsArray { ^[this, this, \lin, 0, this] } + + miSC_decimalStrings { ^this.asFloat.miSC_decimalStrings } +} + diff --git a/Classes/VarGui/extString_1.sc b/Classes/VarGui/extString_1.sc new file mode 100644 index 0000000..25687e0 --- /dev/null +++ b/Classes/VarGui/extString_1.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ String { + + miSC_specAsArray { |synthName, metaKey = \specs, useGlobalSpecs = true| + ^this.asSymbol.miSC_specAsArray(synthName, metaKey, useGlobalSpecs); + } +} diff --git a/Classes/VarGui/extString_2.sc b/Classes/VarGui/extString_2.sc new file mode 100644 index 0000000..5b71fca --- /dev/null +++ b/Classes/VarGui/extString_2.sc @@ -0,0 +1,66 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ String { + + pfuncPbinds { | pBefore, pReplace, pAfter, exclude, excludeGate = true, + excludeDur = false, excludeLegato = false, metaKey = \specs, useGlobalSpecs = true + post = false, trace = false, num = 1 | + ^this.asSymbol.pfuncPbinds(pBefore, pReplace, pAfter, exclude, excludeGate, + excludeDur, excludeLegato, metaKey, useGlobalSpecs, post, trace, num) + } + + sVarGuiSpecs { | ctrBefore, ctrReplace, ctrAfter, exclude, + metaKey = \specs, useGlobalSpecs = true, num = 1 | + ^this.asSymbol.sVarGuiSpecs(ctrBefore, ctrReplace, ctrAfter, exclude, + metaKey, useGlobalSpecs, num) + } + + pVarGuiSpecs { | ctrBefore, ctrReplace, ctrAfter, durCtr = #[0.05, 3, \exp, 0, 0.2], + legatoCtr = #[0.1, 5, \exp, 0, 0.8], exclude, excludeGate = true, + metaKey = \specs, useGlobalSpecs = true, num = 1| + ^this.asSymbol.pVarGuiSpecs(ctrBefore, ctrReplace, ctrAfter, durCtr, legatoCtr, + exclude, excludeGate, metaKey, useGlobalSpecs, num) + } + + sVarGui { | ctrBefore, ctrReplace, ctrAfter, exclude, + metaKey = \specs, useGlobalSpecs = true, num = 1, server| + ^this.asSymbol.sVarGui(ctrBefore, ctrReplace, ctrAfter, exclude, metaKey, + useGlobalSpecs, num, server) + } + + pVarGui { | ctrBefore, ctrReplace, ctrAfter, + durCtr = #[0.05, 3, \exp, 0, 0.2], legatoCtr = #[0.1, 5, \exp, 0, 0.8], + pBefore, pReplace, pAfter, exclude, excludeGate = true, clock, quant, + metaKey = \specs, useGlobalSpecs = true, post = false, trace = false, num = 1| + ^this.asSymbol.pVarGui(ctrBefore, ctrReplace, ctrAfter, durCtr, legatoCtr, + pBefore, pReplace, pAfter, exclude, excludeGate, clock, quant, + metaKey, useGlobalSpecs, post, trace, num) + } + + miSC_defNameAsArray { ^[this] } + +} + + diff --git a/Classes/VarGui/extSymbol_1.sc b/Classes/VarGui/extSymbol_1.sc new file mode 100644 index 0000000..9b6ee82 --- /dev/null +++ b/Classes/VarGui/extSymbol_1.sc @@ -0,0 +1,35 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Symbol { + miSC_getCtrIndex { |argName| + var ctrIndex, synthDesc = SynthDescLib.global.at(this); + (synthDesc.notNil and: { this.asString[0..4] != "temp_" }).if { + ctrIndex = synthDesc.controls.collect({|x| x.name.asSymbol }).indexOf(argName.asSymbol); + }; + ^ctrIndex; + } +} + + diff --git a/Classes/VarGui/extSymbol_2.sc b/Classes/VarGui/extSymbol_2.sc new file mode 100644 index 0000000..0d2cc20 --- /dev/null +++ b/Classes/VarGui/extSymbol_2.sc @@ -0,0 +1,287 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ Symbol { + + miSC_specAsArray { | synthName, metaKey = \specs, useGlobalSpecs = true | + var desc, spec; + + desc = SynthDescLib.global[synthName.asSymbol]; + spec = desc.tryPerform(\metadata).tryPerform(\at, metaKey) ?? + { useGlobalSpecs.if { Spec.specs[this] } }; + spec.isNil.if { SimpleInputError("no spec found for key " ++ this.asString) + .method_(thisMethod).throw; }; + ^spec.miSC_specAsArray + } + + + miSC_expandCtrs { | item, i, metaKey = \specs, useGlobalSpecs = true| + ^item.(i).miSC_specAsArray(this, metaKey, useGlobalSpecs) + } + + miSC_expandCtrPairs { | item, i, metaKey = \specs, useGlobalSpecs = true| + ^item.(i).collect { |x,j| + j.odd.if { this.miSC_expandCtrs(x, metaKey, useGlobalSpecs) }{ x } + } + } + + miSC_findGlobalControlSpec { + var item = Spec.specs[this]; + ^item.isKindOf(ControlSpec).if { item }{ nil }; } + + miSC_getControlTuples { | exclude, metaKey = \specs, useGlobalSpecs = true | + // returns an array of tuples [symbol, n], where n > 1 indicates an arrayed arg + var symbol, desc, controls, maybeValidArrayedArg; + desc = SynthDescLib.global[this]; + desc.isNil.if { + ^SimpleInputError("SynthDef unknown to SynthDescLib.global (forgot to add ?)") + .method_(thisMethod).throw; + }{ + exclude = exclude.asArray; + exclude = exclude ++ this.miSC_controlsToExclude(metaKey, useGlobalSpecs); + + controls = List[]; + maybeValidArrayedArg = false; + desc.controls.do { |control, i| + symbol = control.name.asSymbol; + (symbol == '?').if { + maybeValidArrayedArg.if { + controls.last[1] = controls.last[1] + 1; } + }{ + exclude.includes(symbol).if { + maybeValidArrayedArg = false; + }{ + controls.add([symbol, 1]); + maybeValidArrayedArg = true; + } + } + }; + ^controls + } + } + + + miSC_controlsToExclude { | metaKey = \specs, useGlobalSpecs = true | + // for associated SynthDef: gives List of control name keys with + // (case useGlobalSpecs = true) no metadata and no global ControlSpecs defined + // (case useGlobalSpecs = false) no metadata defined + + var desc, controls, controlsToExclude = List.new, key, specData; + desc = SynthDescLib.global[this]; + controls = desc.controls; + controls.do { |controlName| + key = controlName.name.asSymbol; + (key != '?').if { + specData = desc.metadata.tryPerform(\at, metaKey).tryPerform(\at, key); + specData.isNil.if { + (useGlobalSpecs.not or: { key.miSC_findGlobalControlSpec.isNil }).if { + controlsToExclude.add(key) } + } + } + }; + ^controlsToExclude + } + + miSC_sVarGuiSpecsFromTuples { | tuples, exclude, metaKey = \specs | + + // expects SequenceableCollection of tuples [symbol, n], + // where n > 1 indicates an arrayed arg + + // miSC_pfuncPbindsFromTuples and miSC_sVarGuiSpecsFromTuples exist + // to avoid multiple lookups in SynthDef metadata by pVarGui + + var specData, varGuiSpecs = List.new, key, num; + + tuples.do { |keyNumPair| + #key, num = keyNumPair; + varGuiSpecs.add(key); + specData = SynthDescLib.global[this].metadata.tryPerform(\at, metaKey).tryPerform(\at, key); + specData.isNil.if { + (specData = key.miSC_findGlobalControlSpec).isNil.if { + SimpleInputError("no metaData for key " ++ key.asString).method_(thisMethod).throw; + } + }; + specData = specData.miSC_specAsArray; + (num > 1).if { specData = specData ! num }; + varGuiSpecs.add(specData); + }; + ^varGuiSpecs + } + + + pfuncPbinds { | pBefore, pReplace, pAfter, exclude, excludeGate = true, + excludeDur = false, excludeLegato = false, metaKey = \specs, useGlobalSpecs = true, + post = false, trace = false, num = 1 | + var excludeI, controlTuples, excludeFreq, pitchKeys = #[\note, \midinote, \degree]; + pBefore = pBefore ?? []; + pReplace = pReplace ?? []; + pAfter = pAfter ?? []; + exclude = exclude ?? []; + + ^num.collect { |i| + + // detect reserved pbind pitch controls that determine freq, then set flag excludeFreq + excludeFreq = pitchKeys.any { |k| pBefore.(i).includes(k) or: { pAfter.(i).includes(k) } }; + excludeI = exclude.(i).asArray; + + // controls without defined metadata / associated global ControlSpec are excluded, + // they could be included as explicitely given pattern pairs and controls + + controlTuples = this.miSC_getControlTuples( + excludeI ++ (excludeGate.(i).if { [\gate] }{ [] }) ++ + (excludeFreq.if { [\freq] }{ [] }), + metaKey.(i), useGlobalSpecs.(i) + ); + + controlTuples.miSC_pfuncPbindsFromTuples( + pBefore.(i), pReplace.(i), pAfter.(i), this, + excludeI.includes(\dur), excludeI.includes(\legato), post.(i), trace.(i) + ); + }; + } + + + sVarGuiSpecs { | ctrBefore, ctrReplace, ctrAfter, exclude, + metaKey = \specs, useGlobalSpecs = true, num = 1 | + var excludeI, controlTuples, expand, + ctrs = Array.newClear(num), replaceIndex; + + ctrBefore = ctrBefore ?? []; + ctrReplace = ctrReplace ?? []; + ctrAfter = ctrAfter ?? []; + exclude = exclude ?? []; + + num.do { |i| + excludeI = exclude.(i).asArray; + controlTuples = this.miSC_getControlTuples( + excludeI, metaKey.(i), useGlobalSpecs.(i) + ); + expand = { |x| this.miSC_expandCtrPairs(x, i, metaKey.(i), useGlobalSpecs.(i)) }; + + ctrs[i] = expand.(ctrBefore) ++ + this.miSC_sVarGuiSpecsFromTuples(controlTuples, excludeI, metaKey.(i)) ++ + expand.(ctrAfter); + + expand.(ctrReplace) + .pairsDo { |key, ctr| + replaceIndex = ctrs[i].indexOf(key); + replaceIndex.notNil.if { ctrs[i][replaceIndex + 1] = ctr }; + }; + }; + ^ctrs; + } + + pVarGuiSpecs { | ctrBefore, ctrReplace, ctrAfter, durCtr = #[0.05, 3, \exp, 0, 0.2], + legatoCtr = #[0.1, 5, \exp, 0, 0.8], exclude, excludeGate = true, + metaKey = \specs, useGlobalSpecs = true, num = 1| + + ^this.sVarGuiSpecs({ |i| ctrBefore.(i) ++ [\dur, durCtr.(i), \legato, legatoCtr.(i)] }, + ctrReplace, ctrAfter, { |i| exclude.(i).asArray ++ (excludeGate.(i).if { [\gate] }{ [] }) }, + metaKey, useGlobalSpecs, num); + } + + + sVarGui { | ctrBefore, ctrReplace, ctrAfter, exclude, + metaKey = \specs, useGlobalSpecs = true, num = 1, server| + ^VarGui( + synthCtr: this.sVarGuiSpecs(ctrBefore, ctrReplace, ctrAfter, exclude, + metaKey, useGlobalSpecs, num), + synth: this ! num, + server: server + ); + } + + + miSC_pVarGuiData { | ctrBefore, ctrReplace, ctrAfter, + durCtr = #[0.05, 3, \exp, 0, 0.2], legatoCtr = #[0.1, 5, \exp, 0, 0.8], + pBefore, pReplace, pAfter, exclude, excludeGate = true, clock, quant, + metaKey = \specs, useGlobalSpecs = true, post = false, trace = false, num = 1| + + var addedPairs, excludeI, controlTuples, excludeFreq = false, + pitchKeys = #[\note, \midinote, \degree], expand1, expand2, + ctrs = Array.newClear(num), streams = Array.newClear(num), replaceIndex; + + ctrBefore = ctrBefore ?? []; + ctrReplace = ctrReplace ?? []; + ctrAfter = ctrAfter ?? []; + pBefore = pBefore ?? []; + pReplace = pReplace ?? []; + pAfter = pAfter ?? []; + exclude = exclude ?? []; + + num.do { |i| + // detect reserved pbind pitch controls that determine freq, then set flag excludeFreq + excludeFreq = pitchKeys.any { |k| pBefore.(i).includes(k) or: { pAfter.(i).includes(k) } }; + excludeI = exclude.(i).asArray; + + // controls without defined metadata / associated global ControlSpec are excluded, + // they could be included as explicitely given pattern pairs and controls + + controlTuples = this.miSC_getControlTuples( + excludeI ++ (excludeGate.(i).if { [\gate] }{ [] }) ++ + (excludeFreq.if { [\freq] }{ [] }), + metaKey.(i), useGlobalSpecs.(i) + ); + + expand1 = { |x| this.miSC_expandCtrPairs(x, i, metaKey.(i), useGlobalSpecs.(i)) }; + expand2 = { |x| this.miSC_expandCtrs(x, i, metaKey.(i), useGlobalSpecs.(i)) }; + + ctrs[i] = expand1.(ctrBefore) ++ + (excludeI.includes(\dur).not.if { + [\dur, expand2.(durCtr.(i))] }{ [] }) ++ + (excludeI.includes(\legato).not.if { + [\legato, expand2.(legatoCtr.(i))] }{ [] }) ++ + this.miSC_sVarGuiSpecsFromTuples(controlTuples, excludeI, metaKey.(i)) ++ + expand1.(ctrAfter); + + + expand1.(ctrReplace) + .pairsDo { |key, ctr| + replaceIndex = ctrs[i].indexOf(key); + replaceIndex.notNil.if { ctrs[i][replaceIndex + 1] = ctr }; + }; + + streams[i] = controlTuples.miSC_pfuncPbindsFromTuples( + pBefore.(i), pReplace.(i), pAfter.(i), this, + excludeI.includes(\dur), excludeI.includes(\legato), post.(i), trace.(i) + ); + }; + ^[ctrs, streams, num.collect(clock.(_)), num.collect(quant.(_))] + } + + pVarGui { | ctrBefore, ctrReplace, ctrAfter, + durCtr = #[0.05, 3, \exp, 0, 0.2], legatoCtr = #[0.1, 5, \exp, 0, 0.8], + pBefore, pReplace, pAfter, exclude, excludeGate = true, clock, quant, + metaKey = \specs, useGlobalSpecs = true, post = false, trace = false, num = 1| + + var data = this.miSC_pVarGuiData(ctrBefore, ctrReplace, ctrAfter, durCtr, legatoCtr, + pBefore, pReplace, pAfter, exclude, excludeGate, clock, quant, metaKey, + useGlobalSpecs, post, trace, num); + + ^VarGui(data[0], stream: data[1], clock: data[2], quant: data[3]); + } + +} + + diff --git a/Classes/VarGui/extSynth.sc b/Classes/VarGui/extSynth.sc new file mode 100644 index 0000000..7d16385 --- /dev/null +++ b/Classes/VarGui/extSynth.sc @@ -0,0 +1,30 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++Synth { + + miSC_getCtrIndex { |argName| ^this.defName.asSymbol.miSC_getCtrIndex(argName) } +} + + diff --git a/Classes/VarGui/extVarGuiPlayerSection.sc b/Classes/VarGui/extVarGuiPlayerSection.sc new file mode 100644 index 0000000..c00b49d --- /dev/null +++ b/Classes/VarGui/extVarGuiPlayerSection.sc @@ -0,0 +1,84 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++VarGuiPlayerSection { + + drawPlayers { + + iconViewGroup[0].drawFunc = { + var playX1 = 0.38, playY1 = 0.3, fac = 1, + x = iconViewGroup[0].bounds.width, y = iconViewGroup[0].bounds.height; + Pen.moveTo(Point(x * playX1, y * playY1)); + Pen.lineTo(Point(x * (1-playX1), y * 0.5)); + Pen.lineTo(Point(x * playX1, (1-playY1) * y)); + Pen.width = 1.4 * fac; + Pen.strokeColor = Color.black; + Pen.stroke; + }; + + iconViewGroup[1].drawFunc = { + var playX2 = 0.43, playY2 = 0.2, fac = 1, + x = iconViewGroup[1].bounds.width, y = iconViewGroup[1].bounds.height; + Pen.moveTo(Point(x * playX2, y * playY2)); + Pen.lineTo(Point(x * playX2, y * (1-playY2))); + Pen.moveTo(Point(x * (1-playX2), y * playY2)); + Pen.lineTo(Point(x * (1-playX2), y * (1-playY2))); + Pen.width = 1.7 * fac; + Pen.strokeColor = Color.black; + Pen.stroke; + }; + + iconViewGroup[2].drawFunc = { + var playX3a = 0.16, playX3a2 = 0.32, playY3a = 0.3, playX3b = 0.45, playY3b = 0.9, playX3c = 0.64, playY3c = 0.3, fac = 1, + x = iconViewGroup[2].bounds.width, y = iconViewGroup[2].bounds.height; + + Pen.moveTo(Point(x * playX3a, y * playY3a)); + Pen.lineTo(Point(x * playX3a, y * (1-playY3a))); + Pen.lineTo(Point(x * playX3a2, y * (1-playY3a))); + Pen.lineTo(Point(x * playX3a2, y * playY3a)); + Pen.lineTo(Point(x * playX3a - (1 * fac), y * playY3a)); + + Pen.width = 1.4 * fac; + Pen.strokeColor = Color.black; + Pen.stroke; + + Pen.moveTo(Point(x * playX3b, y * playY3b)); + Pen.lineTo(Point(x * (1-playX3b), y * (1-playY3b))); + + Pen.width = 1 * fac; + Pen.strokeColor = Color.black; + Pen.stroke; + + Pen.moveTo(Point(x * (1-playX3a), y * playY3c)); + Pen.lineTo(Point(x * playX3c, y * 0.5)); + Pen.lineTo(Point(x * (1-playX3a), y * (1-playY3c))); + + Pen.width = 1.2 * fac; + Pen.strokeColor = Color.black; + Pen.stroke; + }; + ^this + } + +} diff --git a/Classes/VarGui/extVarGui_1.sc b/Classes/VarGui/extVarGui_1.sc new file mode 100644 index 0000000..49a838f --- /dev/null +++ b/Classes/VarGui/extVarGui_1.sc @@ -0,0 +1,385 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++VarGui { + + checkSingleSynthInput { |synth| + case + { [Symbol, String].any(synth.isKindOf(_)) } + { + SynthDescLib.global[synth.asSymbol].isNil.if { + SimpleInitError("Synth given as " ++ synth.class.asString ++ " " ++ synth.asString ++ + " not contained " ++ + "in global SynthDescLib (forgot SynthDef.add, former .memStore ?)") + .class_(VarGui).throw; + } + } + { [Synth, Integer].any(synth.isKindOf(_)).not } + { SimpleInitError("Single synth input item must be synthdef (given as Symbol or String) or " ++ + "Synth (directly or as nodeID integer)").class_(VarGui).throw }; + ^this + } + + // not a complete input check, but avoid some nearby discrepances + + checkArgs {|varCtr, synthCtr, stream, synth, varEnvirGroups, envir, + synthCtrGroups, assumePlaying, assumeRunning, assumeEnded| + var j = 0, c, vars, synthCtrs, envirSet, synthStateVars, synthStateStrings, synthInputDup = false, result; + + case + { synth.isNil } + { + (this.synthCtr.size != 0).if { + SimpleInitError("synthCtr input but no synth input. " ++ + "Synth must be Symbol, String (indicating a Synthdef known by SynthDesLib), " ++ + "Synth or Integer (nodeID) or collection thereof.").class_(VarGui).throw; + }{ + synths = []; + }; + } + { synth.isKindOf(SequenceableCollection) } + { + synths = synth; + } + { [Synth, Integer, Symbol, String].any(synth.isKindOf(_)) } + { + synths = [synth]; + } + { true }{ SimpleInitError("Synth must be Symbol, String (indicating a Synthdef known by SynthDesLib), " ++ + "Synth or Integer (nodeID) or collection thereof.").class_(VarGui).throw; }; + + synths.do {|x| this.checkSingleSynthInput(x) }; + + + // prepare use of metadata for synthCtr if necessary + + (synthCtr.isNil && synth.notNil).if { synthCtr = (nil ! max(1, synth.size)) }; + + (synthCtr.isKindOf(SequenceableCollection) and: { synthCtr.size > 0 } and: + { (synthCtr.first.isSequenceableCollection) || (synthCtr.first.isNil) }).if { + synthCtr.do { |specPairs, i| + var sym; + specPairs.isNil.if { + synthCtr[i] = case + { [Symbol, String].any(synths[i].isKindOf(_)) } + { synths[i].asSymbol.sVarGuiSpecs.flatten; } + { synths[i].isKindOf(Synth) } + { + sym = synths[i].defName.asSymbol; + SynthDescLib.global[sym].notNil.if { + sym.sVarGuiSpecs.flatten; + }{ + [] + }; + }; + specPairs = synthCtr[i]; + } + } + }; + + + // this.synthCtr stores flattened (ungrouped) ctrs + + this.synthCtr = case + { synthCtr.isNil }{ [] } + { synthCtr.first.isKindOf(SequenceableCollection) }{ + // check if ctrs given as keys to be looked up as global ControlSpec + c = synthCtr.flatten; + c.do { |item, i| i.odd.if { c[i] = c[i].miSC_specAsArray } }; + } + { true }{ synthCtr }; + + + synthCtrs = this.synthCtr.select {|x,i| i.even }; + + + synthStateVars = [assumePlaying, assumeRunning, assumeEnded]; + synthStateStrings = ["assumePlaying", "assumeRunning", "assumeEnded"]; + + synthStateStrings.do {|x,i| + case + { synthStateVars[i].isKindOf(SequenceableCollection) } + { + (synthStateVars[i].every {|x| [Boolean, Nil].any(x.isKindOf(_)) } && + (synthStateVars[i].size == synths.size)).not.if { + SimpleInitError(x ++ " input as collection must equal number of synths, " ++ + "items must be Boolean or Nil").class_(VarGui).throw; + }{ + this.perform((x ++ "_").asSymbol, synthStateVars[i]); + } + } + { [Boolean, Nil].any(synthStateVars[i].isKindOf(_)) } + { + this.perform((x ++ "_").asSymbol, synthStateVars[i].dup(synths.size)); + } + { true }{ SimpleInitError(x ++ " must be Boolean, Nil or collection thereof, " ++ + "in this case size must corespond with synthCtr").class_(VarGui).throw; }; + }; + + this.assumeEnded.do {|x,i| + ((x == true) && ((this.assumePlaying[i] == true) || (this.assumeRunning[i] == true))).if { + SimpleInitError("Contradictory assumptions about synth state, there must not be a player " ++ " + with assumeEnded set true " ++ + "together with assumePlaying or " ++ "assumeRunning set true").class_(VarGui).throw; + }; + ((this.assumePlaying[i] == false) && (this.assumeRunning[i] == true)).if { + SimpleInitError("Contradictory assumptions about synth state, there must not be a " ++ " + player with assumePlaying set false " ++ + "and assumeRunning set true").class_(VarGui).throw; + }; + }; + + synthStateStrings.do {|x,i| + this.perform(x.asSymbol).do {|y,j| + (([Symbol, String].any(synths[j].isKindOf(_))) && (y.notNil)).if { + SimpleInitError("There must not be any assume flag set to a Boolean for a " ++ " + Symbol / String as synth input, " ++ + "assumptions are only allowed for Synths and nodeIDs.").class_(VarGui).throw; + } + } + }; + + synthIDs = synths.collect {|x| [Synth, Integer].any(x.isKindOf(_)).if { x.asNodeID } }; + + stream = stream.miSC_defNameAsArray; + streamEnvirs = List.new; + streamEnvirIndices = Array.newClear(stream.size); + streams = Array.newClear(stream.size); + + stream.do {|x, i| + var e, k; + case + { x.isKindOf(Function) }{ e = Environment.new; streams[i] = e.use { Task(x) } } + { x.isKindOf(Pattern) }{ e = Environment.new; streams[i] = e.use { x.asEventStreamPlayer } } + { x.isKindOf(Symbol) || x.isKindOf(String) } + { e = Environment.new; streams[i] = e.use { x.asSymbol.pfuncPbinds.at(0).asEventStreamPlayer } } + { true }{ + x.isKindOf(PauseStream).not.if { + SimpleInitError("Stream must be Task, Task function, Pattern, " ++ + "EventStreamPlayer, Symbol, String or collection of such").class_(VarGui).throw; + }{ + e = x.originalStream.miSC_getEnvironment; + k = streamEnvirs.detectIndex(_ === e); + streams[i] = x; + } + }; + k.notNil.if { + streamEnvirIndices[i] = k; + }{ + streamEnvirs = streamEnvirs.add(e); + streamEnvirIndices[i] = j; + j = j + 1; + }; + }; + + envir.isNil.if { + envirs = (stream.size == 0).if { [currentEnvironment] }{ streamEnvirs }; + }{ + (stream.size != 0).if { SimpleInitError("Passing an envir arg only " ++ + "allowed without stream players").class_(VarGui).throw }; + envirs = case + { envir.isKindOf(Environment) }{ [envir] } + { envir.isSequenceableCollection }{ envir } + { true }{ SimpleInitError("Envir arg must be Environment or SequenceableCollection") + .class_(VarGui).throw; }; + + envirSet = IdentitySet.new; + envirs.do { |envir| envirSet = envirSet.add(envir) }; + + ((envirs.any(_.isKindOf(Environment).not)) || (envirSet.size != envirs.size)).if { + SimpleInitError("Envir arg must be Environment or SequenceableCollection of " ++ + "non-identical Environments").class_(VarGui).throw; + }; + + }; + + + // prepare use of metadata for varCtr if necessary + // this.varCtr stores flattened (ungrouped) ctrs + + (varCtr.isNil && stream.notNil).if { varCtr = (nil ! max(1, stream.size)) }; + + (varCtr.isKindOf(SequenceableCollection) and: { varCtr.size > 0 } and: + { (varCtr.first.isSequenceableCollection) || (varCtr.first.isNil) }).if { + + // case grouped varCtr input, some items may be nil, will look for metadata then + varEnvirGroups.notNil.if { + SimpleInitError("varEnvirGroups must not be given if varCtr is already grouped, " ++ + "means a collection of specPair collections").class_(VarGui).throw; + }; + hasConnectedVarEnvirGroups = true; + envir.isNil.if { + (stream.size != 0).if { + ((varCtr.size) > (streamEnvirs.size)).if { + SimpleInitError("Size of varCtr exceeds number of implicitely given stream envirs") + .class_(VarGui).throw; + } + }{ + ((varCtr.size) > 1).if { + SimpleInitError("Size of varCtr > 1 but no implicitely or explicitely given envirs") + .class_(VarGui).throw; + } + } + }{ // can only happen if no streams + ((varCtr.size) > (envirs.size)).if { + SimpleInitError("Size of varCtr exceeds number of explicitely given envirs") + .class_(VarGui).throw; + }; + }; + varCtr.do { |specPairs, i| + var envirKeys, c; + + specPairs.isNil.if { + varCtr[i] = ([Symbol, String].any(stream[i].isKindOf(_))).if { + stream[i].asSymbol.pVarGuiSpecs.flatten; + }{ + [] + }; + specPairs = varCtr[i]; + }; + + this.varCtr = varCtr.flatten; + + specPairs.do { |item, j| + j.even.if { + varEnvirIndices = varEnvirIndices.add(i); + envirKeys = envirKeys.add(item); + } + }; + (envirKeys.miSC_asSet.size != envirKeys.size).if { + SimpleInitError("Bad definition: specPairs defined for one envir contain " ++ + "var name more than once").class_(VarGui).throw; + } + }; + vars = this.varCtr.select {|x,i| i.even }; + + }{ + + this.varCtr = varCtr.isNil.if { [] }{ varCtr }; + vars = this.varCtr.select {|x,i| i.even }; + + varEnvirGroups.isNil.if { + (vars.size != vars.miSC_asSet.size).if { + SimpleInitError("varCtr contains multiple keys but varEnvirGroups not defined") + .class_(VarGui).throw; + }; + hasConnectedVarEnvirGroups = true; + varEnvirIndices = vars.size.collect { 0 }; + }{ + varEnvirGroups.miSC_isGrouping(vars.size).not.if { + SimpleInitError("varEnvirGroups must be a valid grouping of number of vars. " ++ + "E.g. [[3,0], [1,2,4]] is a valid grouping of 5").class_(VarGui).throw; + }; + hasConnectedVarEnvirGroups = varEnvirGroups.miSC_isConnected; + (varEnvirGroups.size > envirs.size).if { + SimpleInitError("Size of varEnvirGroups must less or equal " ++ envirs.size.asString ++ + ", the number of " ++ (envir.notNil.if { "ex" }{ "im" }) ++ "plicitely given envirs") + .class_(VarGui).throw; + }; + varEnvirIndices = Array.newClear(vars.size); + varEnvirGroups.do { |x,i| + var y = vars[x]; + (y.size != y.miSC_asSet.size).if { + SimpleInitError("Bad definition: envirGroup " ++ x.asString ++ + " contains var name more than once").class_(VarGui).throw; + }; + x.do(varEnvirIndices[_] = i); + }; + }; + }; + // check if ctrs given as keys to be looked up as global ControlSpec + this.varCtr.do { |item, i| i.odd.if { this.varCtr[i] = this.varCtr[i].miSC_specAsArray } }; + + synthCtr.first.isSequenceableCollection.if { + synthCtrGroups.notNil.if { + SimpleInitError("synthCtrGroups must not be given if synthCtr is already grouped, " ++ + "means a collection of specPair collections").class_(VarGui).throw; + }; + hasConnectedSynthCtrGroups = true; + + (synthCtr.size > synths.size).if { + SimpleInitError("Size of synthCtr exceeds number of given synths").class_(VarGui).throw; + }; + synthCtr.do { |specPairs, i| + var synthKeys; + specPairs.do { |item, j| + j.even.if { + synthCtrSynthIndices = synthCtrSynthIndices.add(i); + synthKeys = synthKeys.add(item); + } + }; + (synthKeys.miSC_asSet.size != synthKeys.size).if { + SimpleInitError("Bad definition: specPairs defined for one synth " ++ + "contain ctr name more than once").class_(VarGui).throw; + } + }; + + }{ + synthCtrGroups.isNil.if { + (synthCtrs.size != synthCtrs.miSC_asSet.size).if { + SimpleInitError("synthCtr contains multiple keys but synthCtrGroups not defined") + .class_(VarGui).throw; + }; + hasConnectedSynthCtrGroups = true; + synthCtrSynthIndices = synthCtrs.size.collect { 0 }; + }{ + synthCtrGroups.miSC_isGrouping(synthCtrs.size).not.if { + SimpleInitError("synthCtrGroups must be a valid grouping of number of synthCtrs. " ++ + "E.g. [[3,0], [1,2,4]] is a valid grouping of 5").class_(VarGui).throw; + }; + hasConnectedSynthCtrGroups = synthCtrGroups.miSC_isConnected; + (synthCtrGroups.size > synths.size).if { + SimpleInitError("Size of synthCtrGroups must be less or equal " ++ synths.size.asString ++ + ", the number of given synths").class_(VarGui).throw; + }; + synthCtrSynthIndices = Array.newClear(synthCtrs.size); + synthCtrGroups.do { |x,i| + var y = synthCtrs[x]; + (y.size != y.miSC_asSet.size).if { + SimpleInitError("Bad definition: synthCtrGroup " ++ x.asString ++ + " contains synth controlname more than once").class_(VarGui).throw; + }; + x.do(synthCtrSynthIndices[_] = i); + }; + }; + }; + + // check if ctrs given as keys to be looked up as global ControlSpec + this.synthCtr.do { |item, i| i.odd.if { this.synthCtr[i] = this.synthCtr[i].miSC_specAsArray } }; + + hasConnectedSynthCtrGroups.if { + firstSynthCtrIndices = synths.collect { |synth, i| synthCtrSynthIndices.tryPerform(\indexOf,i) }; + }; + + (envir.notNil && (varEnvirIndices.miSC_asSet.size < envirs.size)).if { + SimpleInitError("Bad definition: unused explicitely given envirs").class_(VarGui).throw; + }; + + varColorNum = varEnvirIndices.miSC_asSet.size; + synthColorNum = synthCtrSynthIndices.miSC_asSet.size; + + ^this; + } +} + diff --git a/Classes/VarGui/extVarGui_2.sc b/Classes/VarGui/extVarGui_2.sc new file mode 100644 index 0000000..937a99f --- /dev/null +++ b/Classes/VarGui/extVarGui_2.sc @@ -0,0 +1,141 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++VarGui { + + possibleColumnBreakIndices {|sliderPriority, allowSynthsBreak, allowVarsBreak, + allowSynthBreak, allowArrayBreak, allowEnvirBreak, minPartitionSize| + var possibleVarBreakIndices = [], possibleSynthBreakIndices = [], possibleBreakIndices, modSynthCtr, modSynthCtrNums, + indOffset, indices1, indices2, priority, + k = 0, // iterate controls + l = 0; // iterate vars + + // collection [0] means possible break if there are controls of other type before + // []: don't break apart this control type + + priority = case + { sliderPriority.asSymbol == \var }{ \var } + { sliderPriority.asSymbol == \synth }{ \synth } + { true }{ Error("sliderPriority must be set to var or synth").throw }; + + modSynthCtr = synthCtr; + modSynthCtrNums = synthCtrNum; + + forBy(0, varCtr.size - 2, 2, {|i| + varCtr[i+1].every(_.isSequenceableCollection).if { + varCtr[i+1].do({|item,j| + if ((k <= (varCtrNum - minPartitionSize)) && + ((k == 0) || + (allowVarsBreak && + (((j == 0) && (k >= minPartitionSize)) || + ((j >= minPartitionSize) && allowArrayBreak && + (j <= ((varCtr[i+1].size - minPartitionSize))) + ) + ) and: + { allowEnvirBreak || (l == 0) or: { varEnvirIndices[l] != varEnvirIndices[l-1] } } + ) + ),{ + possibleVarBreakIndices = possibleVarBreakIndices.add(k); + } + ); + k = k+1; + }) + }{ + if (((k <= (varCtrNum - minPartitionSize)) && + ((k == 0) || + ((k >= minPartitionSize) && + allowVarsBreak and: + { allowEnvirBreak || (l == 0) or: { varEnvirIndices[l] != varEnvirIndices[l-1] } } + ) + )),{ + possibleVarBreakIndices = possibleVarBreakIndices.add(k); + } + ); + k = k+1; + }; + l = l + 1; + }); + + k = 0; // iterate controls + l = 0; // iterate + + forBy(0, synthCtr.size - 2, 2, {|i| + synthCtr[i+1].every(_.isSequenceableCollection).if { + synthCtr[i+1].do({|item,j| + if ((k <= (synthCtrNum - minPartitionSize)) && + ((k == 0) || + (allowSynthsBreak && + (((j == 0) && (k >= minPartitionSize)) || + ((j >= minPartitionSize) && allowArrayBreak && + (j <= ((synthCtr[i+1].size - minPartitionSize))) + ) + ) and: + { allowSynthBreak || (l == 0) or: { synthCtrSynthIndices[l] != synthCtrSynthIndices[l-1] } } + ) + ),{ + possibleSynthBreakIndices = possibleSynthBreakIndices.add(k); + } + ); + k = k+1; + }) + }{ + if (((k <= (synthCtrNum - minPartitionSize)) && + ((k == 0) || + ((k >= minPartitionSize) && + allowSynthsBreak and: + { allowSynthBreak || (l == 0) or: { synthCtrSynthIndices[l] != synthCtrSynthIndices[l-1] } } + ) + )),{ + possibleSynthBreakIndices = possibleSynthBreakIndices.add(k); + } + ); + k = k+1; + }; + l = l + 1; + }); + + + indices1 = (priority == \var).if { possibleVarBreakIndices }{ possibleSynthBreakIndices }; + indices2 = (priority == \var).if { possibleSynthBreakIndices }{ possibleSynthBreakIndices }; + + (priority == \var).if { + indices1 = possibleVarBreakIndices; + indices2 = possibleSynthBreakIndices; + indOffset = varCtrNum; + }{ + indices1 = possibleSynthBreakIndices; + indices2 = possibleVarBreakIndices; + indOffset = synthCtrNum; + }; + + possibleBreakIndices = case + { (indices1.size == 0) && (indices2.size == 0) }{ [] } + { (indices1.size == 0) } + { ((indices2[0] != 0).if { indices2 }{ indices2.drop(1) }) + indOffset } + { true } + { ((indices1[0] != 0).if { indices1 }{ indices1.drop(1) }) ++ (indices2 + indOffset) }; + + ^possibleBreakIndices; + } +} diff --git a/Classes/VarGui/extVarGui_3.sc b/Classes/VarGui/extVarGui_3.sc new file mode 100644 index 0000000..280aa17 --- /dev/null +++ b/Classes/VarGui/extVarGui_3.sc @@ -0,0 +1,228 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + ++VarGui { + + effectiveSliderWidth {|columnNum, maxColumnNum, minSliderWidth, maxSliderWidth| + var k,d; + ^[0,1].includes(columnNum).if { + maxSliderWidth + }{ + k = (maxSliderWidth - minSliderWidth)/(1 - maxColumnNum); + d = maxSliderWidth - k; + columnNum * k + d; + } + } + + placeSliders {|sliderPriority, sliderType, cview, columnBreakIndices, + sliderWidth, sliderHeight, labelWidth, numberWidth, + synthNumWidth, tempColors, numColorExp, columnIndent, + gap, leftMargin, varColorNum, synthColorNum, colorDeviation, greyMode, fontColor| + var k = 0, m = 0, c = 0, r = 0, rMax = 0, columnBreakCheck, placeVarSliders, + placeSynthSliders, afterBreak = false, counterUpdate, sliderClass, + tempCtrColors, orderedCtrColorPairs, colorDeviationNums, synthOffset, varOffset, + nextLinePlusMaybeLabel, mod = 256; + + sliderClass = sliderType.switch( + \standard, { EZSlider }, + \smooth, { EZSmoothSlider }, + \round, { EZRoundSlider } + ); + + // counters: + // m: sliders + // k: slider per type + // c: column + // r, rMax: max row number, also counts gap between var and synth sliders + + cview.keyModifiersChangedAction_({ |view, modifiers| mod = modifiers}); + + colorDeviationNums = Array.newClear(varColorNum + synthColorNum); + + orderedCtrColorPairs = ((varColorNum + synthColorNum) != 0).if { + (sliderPriority == \var).if { + varCtrColorPairs ++ ((synthCtrColorPairs.size != 0).if { synthCtrColorPairs + [[varColorNum, 0]] }) + }{ + synthCtrColorPairs ++ ((varCtrColorPairs.size != 0).if { varCtrColorPairs + [[synthColorNum, 0]] }) + }; + }{ + [] + }; + + orderedCtrColorPairs.do {|x,i| + (colorDeviationNums[x[0]].isNil or: { colorDeviationNums[x[0]] < x[1] }).if { + colorDeviationNums[x[0]] = x[1] + }; + }; + colorDeviationNums = colorDeviationNums + 1; + + tempCtrColors = colorDeviationNums.collect {|x,i| + var c = tempColors[i], p = greyMode.if { (0..x-1).scramble/(x-1) } { x.miSC_distinctCubePoints(3) }; + x.collect({|j| + var q = (greyMode.not.if { p[j] }{ p[j]!3 }).linlin(0,1, 1 / (1 + colorDeviation), (1 + colorDeviation)); + Color(c.red * q[0], c.green * q[1], c.blue * q[2]); + }) + }; + + columnBreakCheck = { |i| + (r > rMax).if { rMax = r }; + (i == columnBreakIndices[c]).if { + cview.decorator.reset; + c = c + 1; + r = 0; + afterBreak = true; + } + }; + + counterUpdate = { + k = k+1; + m = m+1; + r = r+1; + afterBreak = false; + columnBreakCheck.(m); + }; + + nextLinePlusMaybeLabel = {|synthIndex, j, l = 0| + cview.decorator.nextLine; + + (hasConnectedSynthCtrGroups.not or: { ((firstSynthCtrIndices.includes(j) && (l == 0)) || afterBreak) }).if { cview.decorator.shift((sliderWidth + columnIndent) * c - synthNumWidth - gap); + synthNameBoxes = synthNameBoxes.add( + StaticText(cview, Rect(0, 0, synthNumWidth, sliderHeight)) + .background_(tempColors[synthCtrColorPairs[k][0] + synthOffset].miSC_exp(numColorExp)) + .string_( (hasConnectedSynthCtrGroups && afterBreak and: { firstSynthCtrIndices.includes(j).not } ).if { + "(" ++ (synthIndex.asString) ++ ")" + }{ + synthIndex.asString + }) + .align_(\center).stringColor_(fontColor) + ); + }; + /* avoid shift here */ + cview.decorator.left_((sliderWidth + columnIndent) * c + leftMargin); + }; + + placeVarSliders = { + forBy(0, varCtr.size - 2, 2, {|i| + var str, color; + + ((k == 0) && (m != 0) && afterBreak.not).if { r = r+1; cview.decorator.shift(y: sliderHeight + gap); }; + color = tempCtrColors[varCtrColorPairs[k][0] + varOffset].at(varCtrColorPairs[k][1]); + + varCtr[i+1].every(_.isSequenceableCollection).if { + varCtr[i+1].do({|item,j| + str = varCtr[i].asString ++ "[" ++ j.asString ++ "]" ++ " "; + cview.decorator.nextLine; + cview.decorator.shift((sliderWidth + columnIndent) * c); + varStrings = varStrings.add(str); + varCtrSliders = varCtrSliders.add( + sliderClass.new(cview, sliderWidth @ sliderHeight, str, + ControlSpec(*(varCtr[i+1][j].copyFromStart(3))), + {|ez| this.performSliderActions(varCtr[i], ez.value, \var, mod, i.div(2), j) }, + varCtr[i+1][j].at(4), labelWidth: labelWidth, numberWidth: numberWidth + ).miSC_colorize(color, numColorExp, fontColor) + ); + counterUpdate.(); + }) + }{ + str = varCtr[i].asString ++ " "; + cview.decorator.nextLine; + cview.decorator.shift((sliderWidth + columnIndent) * c); + varStrings = varStrings.add(str); + + varCtrSliders = varCtrSliders.add( sliderClass.new(cview, sliderWidth @ sliderHeight, str, + ControlSpec(*varCtr[i+1].copyFromStart(3)), + {|ez| this.performSliderActions(varCtr[i], ez.value, \var, mod, i.div(2), nil) }, + varCtr[i+1].at(4), labelWidth: labelWidth, numberWidth: numberWidth + ).miSC_colorize(color, numColorExp, fontColor) + ); + counterUpdate.(); + }; + }); + }; + + placeSynthSliders = { + forBy(0, synthCtr.size - 2, 2, {|j| + var str, color, synthIndex = synthCtrSynthIndices[j.div(2)]; + + ((k == 0) && (m != 0) && afterBreak.not).if { r = r+1; cview.decorator.shift(y: sliderHeight + gap); }; + color = tempCtrColors[synthCtrColorPairs[k][0] + synthOffset].at(synthCtrColorPairs[k][1]); + + synthCtr[j+1].every(_.isSequenceableCollection).if { + synthCtr[j+1].do({|item,l| + nextLinePlusMaybeLabel.(synthIndex, j.div(2), l); + str = synthCtr[j].asString ++ "[" ++ l.asString ++ "]" ++ " "; + synthCtrStrings = synthCtrStrings.add(str); + synthCtrSliders = synthCtrSliders.add( sliderClass.new(cview, sliderWidth @ sliderHeight, str, + ControlSpec(*synthCtr[j+1][l].copyFromStart(3)), + {|ez| this.performSliderActions(synthCtr[j], ez.value, \synth, mod, j.div(2), l) }, + synthCtr[j+1][l].at(4), labelWidth: labelWidth, numberWidth: numberWidth + ).miSC_colorize(color, numColorExp, fontColor) + ); + counterUpdate.(); + }) + }{ + nextLinePlusMaybeLabel.(synthIndex, j.div(2)); + str = synthCtr[j].asString ++ " "; + synthCtrStrings = synthCtrStrings.add(str); + synthCtrSliders = synthCtrSliders.add( sliderClass.new(cview, sliderWidth @ sliderHeight, str, + ControlSpec(*synthCtr[j+1].copyFromStart(3)), + {|ez| this.performSliderActions(synthCtr[j], ez.value, \synth, mod, j.div(2), nil) }, + synthCtr[j+1].at(4), labelWidth: labelWidth, numberWidth: numberWidth + ).miSC_colorize(color, numColorExp, fontColor) + ); + counterUpdate.(); + } + }); + }; + + (sliderPriority == \var).if { + synthOffset = varColorNum; + varOffset = 0; + placeVarSliders.(); + k = 0; + placeSynthSliders.() + }{ + synthOffset = 0; + varOffset = synthColorNum; + placeSynthSliders.(); + k = 0; + placeVarSliders.(); + }; + + // slider section height + ^rMax * (sliderHeight + gap) + (2 * gap); + } + + refreshVarCtrSliderLabels {|showEnvirIndices = false| + var sliderCount = 0; + varEnvirIndices.do {|x,i| + varCtrSizes[i].do {|j| + varCtrSliders[sliderCount].set(varStrings[sliderCount] ++ (showEnvirIndices.if { " " ++ x.asString }{ "" })); + sliderCount = sliderCount + 1; + } + }; + ^this + } +} diff --git a/Classes/VarGui/extVarGui_4.sc b/Classes/VarGui/extVarGui_4.sc new file mode 100644 index 0000000..4aad1d4 --- /dev/null +++ b/Classes/VarGui/extVarGui_4.sc @@ -0,0 +1,216 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++VarGui { + + performVarArrayActions {|i, k, offset, symbol, value| + var clippedValue; + varCtrSliders[offset + k].value_(value); + clippedValue = varCtrSliders[offset + k].value; + envirs.at(varEnvirIndices[i.div(2)]).at(symbol).put(k, clippedValue); + (saveData[0][i][k]).put(4, clippedValue); + } + + performSynthArrayActions {|j, k, offset, value| + var clippedValue; + synthCtrSliders[offset + k].value_(value); + clippedValue = synthCtrSliders[offset + k].value; + (saveData[1][j][k]).put(4, clippedValue); + } + + + performSliderActions {|symbol, value, reg, mod, symbolIndex, arrayIndex| + // if reg == \var: symbolIndex = index of var + // if reg == \synth: symbolIndex = index of synth + + var msgList, ii, k = 0, sliderOffset = 0, modType, collectType, ctrIndex, synthIndex, clippedValue; + + modType = case + { (mod.isShift) && (mod.isCtrl) }{ 0 } + { (mod.isShift) }{ 1 } + { true }{ 2 }; + + ((reg == \var) || (mod.miSC_isPseudoCaps)).if { + forBy(0, saveData[0].size - 2, 2, {|i| + ii = i.div(2); + (saveData[0][i] == symbol).if { + (((symbolIndex == ii) && (reg == \var)) || (mod.isAlt)).if { + arrayIndex.isNil.if { + varCtrSliders[sliderOffset].value_(value); + clippedValue = varCtrSliders[sliderOffset].value; + envirs.at(varEnvirIndices[ii]).put(symbol, clippedValue); + (saveData[0][i+1]).put(4, clippedValue); + }{ + saveData[0][i+1].do {|x,k| + modType.switch( + 0, { (k <= arrayIndex).if { this.performVarArrayActions(i+1, k, sliderOffset, symbol, value) } }, + 1, { (k >= arrayIndex).if { this.performVarArrayActions(i+1, k, sliderOffset, symbol, value) } }, + 2, { (arrayIndex == k).if { this.performVarArrayActions(i+1, k, sliderOffset, symbol, value) } } + ); + } } + } + }; + sliderOffset = sliderOffset + saveData[0][i+1][0].isSequenceableCollection.if { saveData[0][i+1].size }{ 1 }; + }) + }; + + sliderOffset = 0; + + ((reg == \synth) || (mod.miSC_isPseudoCaps)).if { + forBy(0, saveData[1].size - 2, 2, {|j| + (saveData[1][j] == symbol).if { + + synthIndex = synthCtrSynthIndices[j.div(2)]; + + (((symbolIndex == j.div(2)) && (reg == \synth)) || (mod.isAlt)).if { + arrayIndex.isNil.if { + synthCtrSliders[sliderOffset].value_(value); + clippedValue = synthCtrSliders[sliderOffset].value; + [-1,2].includes(playerSection.synthStates[synthIndex]).not.if { + msgList = msgList.add([\n_set, (synthIDs[synthIndex]).asNodeID, symbol, clippedValue]); + }; + (saveData[1][j+1]).put(4, clippedValue); + }{ + saveData[1][j+1].do {|x,k| + modType.switch( + 0, { (k <= arrayIndex).if { this.performSynthArrayActions(j+1, k, sliderOffset, value) } }, + 1, { (k >= arrayIndex).if { this.performSynthArrayActions(j+1, k, sliderOffset, value) } }, + 2, { (arrayIndex == k).if { this.performSynthArrayActions(j+1, k, sliderOffset, value) } } + ); + }; + + [-1,2].includes(playerSection.synthStates[synthIndex]).not.if { + ctrIndex = synthCtrIndices[j.div(2)]; + collectType = modType.switch( + 0, { 1 }, + 1, { ctrIndex.notNil.if { 2 }{ 3 } }, + 2, { ctrIndex.notNil.if { 0 }{ 1 } } + ); + msgList = msgList.add(this.makeMsgList(synthIDs[synthIndex], symbol, ctrIndex, arrayIndex, collectType, value, j+1)); + }; + + } + } + }; + sliderOffset = sliderOffset + saveData[1][j+1][0].isSequenceableCollection.if { saveData[1][j+1].size }{ 1 }; + }) + }; + + server.listSendBundle(nil, msgList); + ^this; + } + + makeMsgList {|synth, argName, ctrIndex, arrayIndex, collectType, value, saveDataIndex| + // synth may be Synth or nodeID + // collectType expects \up, \down or \this (from arrayIndex) + + var msgList, size = (saveData[1][saveDataIndex]).size; + + // 0: \this && (ctrIndex.notNil) - this + // 1: \down - this + down + // 2: \up && (ctrIndex.notNil) - this + up + // 3: \up && (ctrIndex.isNil) - this + up + down + + collectType.switch( + 0, { ^[\n_set, synth.asNodeID, ctrIndex + arrayIndex, value] }, + 1, { ^[\n_setn, synth.asNodeID, argName, arrayIndex + 1] ++ saveData[1][saveDataIndex][0..arrayIndex].collect(_.at(4)) }, + 2, { ^[\n_setn, synth.asNodeID, ctrIndex + arrayIndex, size - arrayIndex] ++ saveData[1][saveDataIndex][arrayIndex..(size-1)].collect(_.at(4)) }, + 3, { ^[\n_setn, synth.asNodeID, argName, size] ++ saveData[1][saveDataIndex][0..(size-1)].collect(_.at(4)) } + ); + } + + // + // updateVarSliders {|key, varNum = 0, val, indexOffset = 0, updateNow = true| + // // varNum: multiple occurence index, val may be sequenceable collection + // var varStartIndex, sliderStartIndex, slider; + // varStartIndex = this.varCtr.select({|x,i| i.even}).findAll([key]).at(varNum); + // sliderStartIndex = varCtrSizes.keep(max(0, varStartIndex)).sum; + // val.asArray.do {|x,i| + // slider = varCtrSliders[sliderStartIndex + indexOffset + i]; + // slider.value = x; + // updateNow.if { slider.action.value(slider) } + // }; + // ^this + // } + // + // updateSynthSliders {|key, synthIndex, val, indexOffset = 0, updateNow = true| + // // val may be sequenceable collection + // var keyStartIndex, sliderStartIndex, slider; + // keyStartIndex = this.synthCtr.select({|x,i| i.even}).findAll([key]) + // .select { |k| synthCtrSynthIndices[k] == synthIndex }.first; + // sliderStartIndex = synthCtrSizes.keep(max(0, keyStartIndex)).sum; + // val.asArray.do {|x,i| + // slider = synthCtrSliders[sliderStartIndex + indexOffset + i]; + // slider.value = x; + // updateNow.if { slider.action.value(slider) } + // }; + // ^this + // } + + updateSynthSliders {|key, synthIndex, val, indexOffset = 0, updateNow = true| + // val may be sequenceable collection + var sliderStartIndex, slider; + sliderStartIndex = synthSliderDict[synthIndex, key, \sliderIndex]; + + val.asArray.do {|x,i| + slider = synthCtrSliders[sliderStartIndex + indexOffset + i]; + slider.value = x; + updateNow.if { slider.action.value(slider) } + }; + ^this + } + + updateVarSliders {|key, varNum = 0, val, indexOffset = 0, updateNow = true| + // varNum: multiple occurence index, val may be sequenceable collection + var sliderStartIndex, slider; + sliderStartIndex = varSliderDict[key, \varNum, varNum, \sliderIndex]; + + val.asArray.do {|x,i| + slider = varCtrSliders[sliderStartIndex + indexOffset + i]; + slider.value = x; + updateNow.if { slider.action.value(slider) } + }; + ^this + } + + makeSaveValueMsgList {|synthIndex| + var msgList; + saveData[1].do {|item, j| + j.even.if { + (synthCtrSynthIndices[j.div(2)] == synthIndex).if { + saveData[1][j+1][0].isSequenceableCollection.not.if { + msgList = msgList.add([\n_set, (synthIDs[synthIndex]).asNodeID, + saveData[1][j], saveData[1][j+1][4]]); + }{ + msgList = msgList.add(this.makeMsgList(synthIDs[synthIndex], item, nil, + saveData[1][j+1].size - 1, 1, saveData[1][j+1].last.at(4), j+1)); + } + } + } + }; + ^msgList + } + +} + diff --git a/Classes/VarGui/extVarGui_5.sc b/Classes/VarGui/extVarGui_5.sc new file mode 100644 index 0000000..3196412 --- /dev/null +++ b/Classes/VarGui/extVarGui_5.sc @@ -0,0 +1,74 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++SequenceableCollection { + + miSC_partitionIndex { |index| + var i = 0, sum = this.first; + ^(this.size != 0).if { + while { (index + 1) > sum }{ + i = i + 1; + (i == this.size).if { + sum = index + 1; + i = nil; + }{ + sum = sum + this[i]; + } + }; + i; + }; + } +} + ++VarGui { + envirFromSliderIndex { |sliderIndex| + var varIndex = varCtrSizes.miSC_partitionIndex(sliderIndex), envir; + ^envirs[varEnvirIndices[varIndex]]; + } + + addSliderAction { |function, type, index, envir| + // index means sliderIndex + // if type == nil suppose \var + // if index == nil suppose all indices of that type + var view, sliders, i; + type = type ?? \var; + sliders = (type == \var).if { + this.varCtrSliders + }{ + this.synthCtrSliders + }; + (index.isNil.if { sliders }{ sliders[[index]] }).do { |slider, j| + view = slider.sliderView; + i = index ?? j; + envir = envir ?? { + (type == \var).if { + this.envirFromSliderIndex(i) + }{ + currentEnvironment; + } + }; + view.mouseUpAction = function.inEnvir(envir); + }; + } +} diff --git a/Classes/VarGui/extVarGui_6.sc b/Classes/VarGui/extVarGui_6.sc new file mode 100644 index 0000000..b4837e4 --- /dev/null +++ b/Classes/VarGui/extVarGui_6.sc @@ -0,0 +1,176 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + ++ VarGui { + + midiBindVarSlider { |key, varNum, indexOffset, varSliderIndex, ccNum, chan, srcID| + ^MIDIFunc.cc({ |...args| + var val, num, chan, src, spec, slider; + #val, num, chan, src = args; + slider = this.varCtrSliders[varSliderIndex]; + spec = slider.controlSpec; + val = spec.map(val / 127); + + { this.updateVarSliders (key, varNum, val, indexOffset) }.defer; + }, ccNum, chan, srcID); + } + + midiBindSynthSlider { |key, synthIndex, indexOffset, synthSliderIndex, ccNum, chan, srcID| + ^MIDIFunc.cc({ |...args| + var val, num, chan, src, spec, slider; + #val, num, chan, src = args; + slider = this.synthCtrSliders[synthSliderIndex]; + spec = slider.controlSpec; + val = spec.map(val / 127); + + { this.updateSynthSliders (key, synthIndex, val, indexOffset) }.defer; + }, ccNum, chan, srcID); + } + + startMIDIlearn { + var varSliderMIDIFuncs = this.varCtrSliders.collect {}; + // store srcData to allow relearning with different input + var varSliderSrcData = this.varCtrSliders.collect {}; + var varGrouping = this.initVarCtrColorGroups; + var varKeys = this.varCtr.select { |x,i| i.even }; + var varSliderIndexKeyDict = IdentityDictionary.new; + + var synthSliderMIDIFuncs = this.synthCtrSliders.collect {}; + var synthSliderSrcData = this.synthCtrSliders.collect {}; + var synthGrouping = this.initSynthCtrColorGroups; + var synthKeys = this.synthCtr.select { |x,i| i.even }; + var synthSliderIndexKeyDict = IdentityDictionary.new; + var keyOccurences = IdentityDictionary.new, varNum, midiLearnFunc; + var keyIndex = 0, key; + + varGrouping.do { |group, envirIndex| + // need occurence number of keys for updating sliders + + group.do { |x, i| + key = varKeys[keyIndex]; + varNum = keyOccurences[key] ?? { 0 }; + + x.isKindOf(SequenceableCollection).if { + x.do { |item, j| varSliderIndexKeyDict.put(item, [key, j, varNum]) } + }{ + varSliderIndexKeyDict.put(x, [key, 0, varNum]) + }; + varNum = varNum + 1; + keyOccurences.put(key, varNum); + keyIndex = keyIndex + 1; + }; + }; + keyIndex = 0; + + synthGrouping.do { |group, synthIndex| + group.do { |x, i| + x.isKindOf(SequenceableCollection).if { + x.do { |item, j| synthSliderIndexKeyDict.put(item, [synthKeys[keyIndex], j, synthIndex]) } + }{ + synthSliderIndexKeyDict.put(x, [synthKeys[keyIndex], 0, synthIndex]) + }; + keyIndex = keyIndex + 1 + } + }; + + midiLearnFunc = MIDIFunc.cc({ |val, num, chan, src| + { + var srcData = [num, chan, src]; + this.varCtrSliders.do { |slider, i| + slider.sliderView.hasFocus.if { + varSliderMIDIFuncs[i].isKindOf(MIDIFunc).not.if { + varSliderMIDIFuncs[i] = this.midiBindVarSlider( + varSliderIndexKeyDict[i][0], + varSliderIndexKeyDict[i][2], + varSliderIndexKeyDict[i][1], + i, + num, + chan, + src + ); + this.window.onClose_(this.window.onClose <> { + varSliderMIDIFuncs[i].free; + varSliderMIDIFuncs[i] = nil; + }); + varSliderSrcData[i] = srcData; + }{ + (srcData != varSliderSrcData[i]).if { + varSliderMIDIFuncs[i].free; + varSliderMIDIFuncs[i] = nil; + varSliderSrcData[i] = srcData; + } + + } + } + }; + + this.synthCtrSliders.do { |slider, i| + slider.sliderView.hasFocus.if { + synthSliderMIDIFuncs[i].isKindOf(MIDIFunc).not.if { + synthSliderMIDIFuncs[i] = this.midiBindSynthSlider( + synthSliderIndexKeyDict[i][0], + synthSliderIndexKeyDict[i][2], + synthSliderIndexKeyDict[i][1], + i, + num, + chan, + src + ); + this.window.onClose_(this.window.onClose <> { + synthSliderMIDIFuncs[i].free; + synthSliderMIDIFuncs[i] = nil; + }); + synthSliderSrcData[i] = srcData; + }{ + (srcData != synthSliderSrcData[i]).if { + synthSliderMIDIFuncs[i].free; + synthSliderMIDIFuncs[i] = nil; + synthSliderSrcData[i] = srcData; + } + + } + } + } + }.defer + }, nil); + // use instance variable in next version + this.addDependant('midiLearnFunc' -> midiLearnFunc) + } + + stopMIDIlearn { + // use instance variable in next version + var assocs = this.dependants.select { |d| d.isKindOf(Association) and: { d.key == 'midiLearnFunc' } }; + assocs.do { |a| + a.value.free; + this.dependants.remove(a) + } + } + +} + + + + + + diff --git a/Classes/WaveFolding/SmoothClip.sc b/Classes/WaveFolding/SmoothClip.sc new file mode 100755 index 0000000..e603a37 --- /dev/null +++ b/Classes/WaveFolding/SmoothClip.sc @@ -0,0 +1,150 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// Dynamic waveshaping with line and sine fragment: + +// As math is easier for the case lo == -1, hi == +1, +// we regard this case first and do linear mapping / remapping for other bounds: +// Take tangent through zero for abs(x) < given tangent point x0 +// and sine fragment values above x0 and below 1, clip for abs values above 1. +// The transfer function is antisymmetrical, its slope tends to 0 for x -> +-1. +// Source and target range can be shifted with fromLo, fromHi, toLo, toHi. + +// The sine fragment with minimum at x = 1 and f(1) = 1 has the form +// f(x) = p sin(pi/2 x) - p + 1 +// f'(x) = p pi/2 cos(pi/2 x) + +// Thus the tangent through x0 has the form +// p pi/2 cos(pi/2 x0) x = p sin(pi/2 x0) - p + 1 + +// So for a given tangent point 0 <= x0 < 1 we can calculate p as below. + +// 'amount' indicates the amount of smoothing: +// amount == 0: in signal isn't altered +// amount == 1: in signal is shaped by full sine fragment +// amount expected to be >= 0 and <= 1 + + +SmoothClipS : UGen { + + *ar { |in, lo = -1, hi = 1, amount = 0.5, delta = 0.00001| + ^this.multiNew(\audio, in, lo, hi, amount, delta) + } + + *kr { |in, lo = -1, hi = 1, amount = 0.5, delta = 0.00001| + ^this.multiNew(\control, in, lo, hi, amount, delta) + } + + *new1 { |rate, in, lo = -1, hi = 1, amount = 0.5, delta = 0.00001| + var w, p, x0, slope, case, realSmooth, linSig, sineSig, + fromFactor, fromOffset, dif, sum, selector = this.methodSelectorForRate(rate); + + // map to unit range + dif = hi - lo; + sum = hi + lo; + // avoid zero division with lo = hi + dif = max(dif.abs, delta) * ((dif >= DC.perform(selector, 0)) * 2 - 1); + fromFactor = 2 / dif; + fromOffset = fromFactor * hi.neg + 1; + + in = fromFactor * in + fromOffset; + + // this excludes the border case p -> inf for x0 -> 1 + x0 = min(1 - amount, 1 - delta); + + w = x0 * pi * 0.5; + p = 1 / (1 - sin(w) + (w * cos(w))); + slope = p * pi * 0.5 * cos(w); + linSig = slope * in; + sineSig = sin(in.abs * pi * 0.5) - 1 * p + 1 * in.sign; + + // distinct and remap to passed range + case = (in.abs > x0) + (in.abs >= 1) + (in <= -1); + ^Select.perform(selector, case, [ + linSig, + sineSig, + DC.perform(selector, 1), + DC.perform(selector, -1) + ] * dif + sum * 0.5); + } +} + + +// Dynamic waveshaping with quadratic polynomial. + +// As math is easier for the case lo == -1, hi == +1, +// we regard this case first and do linear mapping / remapping for other bounds: +// Take tangent through zero for abs(x) < given tangent point x0 +// and parable values above x0 and below 1, clip for abs values above 1. +// The transfer function is antisymmetrical, its slope tends to 0 for x -> +-1. + +// 'amount' indicates the amount of smoothing: +// amount == 0: in signal isn't altered +// amount == 1: in signal is shaped by full parable fragment +// amount expected to be >= 0 and <= 1 + +SmoothClipQ : UGen { + *ar { |in, lo = -1, hi = 1, amount = 0.5, delta = 0.00001| + ^this.multiNew(\audio, in, lo, hi, amount, delta) + } + + *kr { |in, lo = -1, hi = 1, amount = 0.5, delta = 0.00001| + ^this.multiNew(\control, in, lo, hi, amount, delta) + } + + *new1 { |rate, in, lo = -1, hi = 1, amount = 0.5, delta = 0.00001| + var p, x0, slope, realSmooth, linSig, parableSig, case, + fromFactor, fromOffset, dif, sum, selector = this.methodSelectorForRate(rate); + + // map to unit range + dif = hi - lo; + sum = hi + lo; + // avoid zero division with lo = hi + dif = max(dif.abs, delta) * ((dif >= DC.perform(selector, 0)) * 2 - 1); + fromFactor = 2 / dif; + fromOffset = fromFactor * hi.neg + 1; + + in = fromFactor * in + fromOffset; + + // this excludes the border case p -> inf for x0 -> 1 + x0 = min(1 - amount, 1 - delta); + + p = 1 / (x0 * x0 - 1); + slope = 2 * p * (x0 - 1); + + linSig = slope * in; + parableSig = (in.abs - 1).squared * p + 1 * in.sign; + + // distinct and remap to passed range + case = (in.abs > x0) + (in.abs >= 1) + (in <= -1); + ^Select.perform(selector, case, [ + linSig, + parableSig, + DC.perform(selector, 1), + DC.perform(selector, -1) + ] * dif + sum * 0.5); + } +} + diff --git a/Classes/WaveFolding/SmoothFold.sc b/Classes/WaveFolding/SmoothFold.sc new file mode 100755 index 0000000..36e1532 --- /dev/null +++ b/Classes/WaveFolding/SmoothFold.sc @@ -0,0 +1,157 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +// SmoothFoldS uses sine smoothing SmoothClipS at corners + +SmoothFoldS : UGen { + *ar { |in, lo = -1, hi = 1, foldRange = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\audio, in, lo, hi, foldRange, smoothAmount, delta) + } + + *kr { |in, lo = -1, hi = 1, foldRange = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\control, in, lo, hi, foldRange, smoothAmount, delta) + } + + *new1 { |rate, in, lo = -1, hi = 1, foldRange = 1, smoothAmount = 0.5, delta = 0.00001| + var case, foldRangeAbs, thr_1, thr_2, selector = this.methodSelectorForRate(rate); + + // case = 0 for inSig in [lo, hi], 1 for inSig < lo and 2 for inSig > hi + case = (in < lo) + (in > hi * 2); + + // thr_1 is the upper limit of the lower fold range + // thr_2 is the lower limit of the upper fold range + // thr_2 can be smaller than thr_1 + + foldRangeAbs = (hi - lo) * foldRange; + thr_1 = lo + foldRangeAbs; + thr_2 = hi - foldRangeAbs; + + ^Select.perform(selector, case, [ + SmoothClipS.perform(selector, in, lo, hi, smoothAmount, delta), + SmoothClipS.perform(selector, Fold.perform(selector, in, lo, thr_1), lo, thr_1, smoothAmount, delta), + SmoothClipS.perform(selector, Fold.perform(selector, in, thr_2, hi), thr_2, hi, smoothAmount, delta) + ]); + } +} + +// variant with two border ranges + +SmoothFoldS2 : UGen { + *ar { |in, lo = -1, hi = 1, foldRangeLo = 1, foldRangeHi = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\audio, in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta) + } + + *kr { |in, lo = -1, hi = 1, foldRangeLo = 1, foldRangeHi = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\control, in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta) + } + + *new1 { |rate, in, lo = -1, hi = 1, foldRangeLo = 1, foldRangeHi = 1, smoothAmount = 0.5, delta = 0.00001| + var case, rangeAbs, thr_1, thr_2, selector = this.methodSelectorForRate(rate); + + // case = 0 for inSig in [lo, hi], 1 for inSig < lo and 2 for inSig > hi + case = (in < lo) + (in > hi * 2); + + // thr_1 is the upper limit of the lower fold range + // thr_2 is the lower limit of the upper fold range + // thr_2 can be smaller than thr_1 + + rangeAbs = hi - lo; + thr_1 = lo + (rangeAbs * foldRangeLo); + thr_2 = hi - (rangeAbs * foldRangeHi); + + ^Select.perform(selector, case, [ + SmoothClipS.perform(selector, in, lo, hi, smoothAmount, delta), + SmoothClipS.perform(selector, Fold.perform(selector, in, lo, thr_1), lo, thr_1, smoothAmount, delta), + SmoothClipS.perform(selector, Fold.perform(selector, in, thr_2, hi), thr_2, hi, smoothAmount, delta) + ]); + } +} + + +// SmoothFoldQ uses quadratic smoothing SmoothClipQ at corners + +SmoothFoldQ : UGen { + *ar { |in, lo = -1, hi = 1, foldRange = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\audio, in, lo, hi, foldRange, smoothAmount, delta) + } + + *kr { |in, lo = -1, hi = 1, foldRange = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\control, in, lo, hi, foldRange, smoothAmount, delta) + } + + *new1 { |rate, in, lo = -1, hi = 1, foldRange = 1, smoothAmount = 0.5, delta = 0.00001| + var case, foldRangeAbs, thr_1, thr_2, selector = this.methodSelectorForRate(rate); + + // case = 0 for inSig in [lo, hi], 1 for inSig < lo and 2 for inSig > hi + case = (in < lo) + (in > hi * 2); + + // thr_1 is the upper limit of the lower fold range + // thr_2 is the lower limit of the upper fold range + // thr_2 can be smaller than thr_1 + + foldRangeAbs = (hi - lo) * foldRange; + thr_1 = lo + foldRangeAbs; + thr_2 = hi - foldRangeAbs; + + ^Select.perform(selector, case, [ + SmoothClipQ.perform(selector, in, lo, hi, smoothAmount, delta), + SmoothClipQ.perform(selector, Fold.perform(selector, in, lo, thr_1), lo, thr_1, smoothAmount, delta), + SmoothClipQ.perform(selector, Fold.perform(selector, in, thr_2, hi), thr_2, hi, smoothAmount, delta) + ]); + } +} + +// variant with two border ranges + +SmoothFoldQ2 : UGen { + *ar { |in, lo = -1, hi = 1, foldRangeLo = 1, foldRangeHi = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\audio, in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta) + } + + *kr { |in, lo = -1, hi = 1, foldRangeLo = 1, foldRangeHi = 1, smoothAmount = 0.5, delta = 0.00001| + ^this.multiNew(\control, in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta) + } + + *new1 { |rate, in, lo = -1, hi = 1, foldRangeLo = 1, foldRangeHi = 1, smoothAmount = 0.5, delta = 0.00001| + var case, rangeAbs, thr_1, thr_2, selector = this.methodSelectorForRate(rate); + + // case = 0 for inSig in [lo, hi], 1 for inSig < lo and 2 for inSig > hi + case = (in < lo) + (in > hi * 2); + + // thr_1 is the upper limit of the lower fold range + // thr_2 is the lower limit of the upper fold range + // thr_2 can be smaller than thr_1 + + rangeAbs = hi - lo; + thr_1 = lo + (rangeAbs * foldRangeLo); + thr_2 = hi - (rangeAbs * foldRangeHi); + + ^Select.perform(selector, case, [ + SmoothClipQ.perform(selector, in, lo, hi, smoothAmount, delta), + SmoothClipQ.perform(selector, Fold.perform(selector, in, lo, thr_1), lo, thr_1, smoothAmount, delta), + SmoothClipQ.perform(selector, Fold.perform(selector, in, thr_2, hi), thr_2, hi, smoothAmount, delta) + ]); + } +} diff --git a/Classes/ZeroX/TZeroXBufRd.sc b/Classes/ZeroX/TZeroXBufRd.sc new file mode 100644 index 0000000..91de470 --- /dev/null +++ b/Classes/ZeroX/TZeroXBufRd.sc @@ -0,0 +1,185 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +TZeroXBufRd : AbstractZeroXBufRd { + + *ar { |sndBuf, zeroXBuf, bufMix, trig, zeroX = 0, xNum = 1, xRep = 1, power = 1, mul = 1, add = 0, + rate = 1, dir = 1, interpl = 4, overlapSize = 10, length = inf, maxTime = inf, + att = 0, rel = 1, curve = -4, doneAction = 0| + var thisX, nextX, baseX, sndBufIndex, phase, phaseTrig, phaseOffset, time, env, sndBufs, + zeroXBufs, zeroXDiff, rateSig, dirSig, sndBufIndexSig, bufSize, zeroXBufSize, + outSize, args, trigCount, sig; + + args = [ + zeroX, xNum, xRep, power, mul, add, rate, dir, interpl, overlapSize, + length, maxTime, att, rel, curve, doneAction + ]; + + bufSize = (sndBuf.size == 0).if { 1 }{ sndBuf.size }; + zeroXBufSize = (zeroXBuf.size == 0).if { 1 }{ zeroXBuf.size }; + + (zeroXBufSize != bufSize).if { + SimpleInitError("sizes of sndBuf and zeroXBuf (single channel buffers!) must correspond") + .class_(ZeroXBufWr).throw + }; + + // if bufMix is undefined then outSize = bufSize + // else outSize is given by bufMix size + #bufMix, outSize = this.checkBufMix(bufMix, bufSize); + + // args might be passd as Function of drate ugens, then expand + #zeroX, xNum, xRep, power, mul, add, rate, dir, interpl, overlapSize, + length, maxTime, att, rel, curve, doneAction = + this.unbubbleInputIfNecessary(*args); + + this.checkForWrongDrateInput(outSize, zeroX, xNum, xRep, power, mul, add, rate, dir); + #zeroX, xNum, xRep, power, mul, add, rate, dir = + [zeroX, xNum, xRep, power, mul, add, rate, dir] + .collect { |x| x.miSC_Dmultiply2(outSize) }; + + // need everything in outSize + mul = outSize.collect { |i| mul.miSC_maybeWrapAt(i) }; + add = outSize.collect { |i| add.miSC_maybeWrapAt(i) }; + power = outSize.collect { |i| power.miSC_maybeWrapAt(i) }; + + trig = outSize.collect { |i| trig.miSC_maybeWrapAt(i) }; + xNum = outSize.collect { |i| xNum.miSC_maybeWrapAt(i) }; + xRep = outSize.collect { |i| xRep.miSC_maybeWrapAt(i) }; + + trigCount = outSize.collect { |i| PulseCount.ar(trig[i]) - 1 }; + + overlapSize = outSize.collect { |i| overlapSize.miSC_maybeWrapAt(i) }; + length = outSize.collect { |i| length.miSC_maybeWrapAt(i) }; + maxTime = outSize.collect { |i| maxTime.miSC_maybeWrapAt(i) }; + att = outSize.collect { |i| att.miSC_maybeWrapAt(i) }; + rel = outSize.collect { |i| rel.miSC_maybeWrapAt(i) }; + curve = outSize.collect { |i| curve.miSC_maybeWrapAt(i) }; + doneAction = outSize.collect { |i| doneAction.miSC_maybeWrapAt(i) }; + + // interpl always refers to sndBufs, not to bufMix size + interpl = bufSize.collect { |i| interpl.miSC_maybeWrapAt(i) }; + + time = Sweep.ar(Impulse.ar(0)); + + env = EnvGen.ar( + Env.asr(att, 1, rel, curve), + (trigCount + 1 <= length) * (time <= maxTime), + doneAction: doneAction + ); + + // core: + // a bit easier than with ZeroXBufRd, Dunique isn't needed here. + // Some drate ugens are polled more than once, + // we can "multiply" them with Dstutter. + + rate = outSize.collect { |i| + var r = rate.miSC_maybeWrapAt(i); + r.isNumber.if { Dstutter(inf, r) }{ Dstutter(2, r) }; + }; + dir = outSize.collect { |i| + var d = dir.miSC_maybeWrapAt(i); + d.isNumber.if { Dstutter(inf, d) }{ Dstutter(3, d) }; + }; + + zeroXBufs = zeroXBuf.asArray; + sndBufs = sndBuf.asArray; + + // buffer switch option with bufMix + sndBufIndex = bufMix.collect { |b| + b.isNumber.if { Dstutter(inf, b) }{ Dstutter(3, b) } + }; + + // determine distance between zero crossings + zeroX = outSize.collect { |i| Dstutter(2, zeroX.miSC_maybeWrapAt(i)) }; + + thisX = outSize.collect { |i| + Dstutter(2, Dbufrd(Dswitch1(zeroXBufs, sndBufIndex[i]), zeroX[i])); + }; + nextX = outSize.collect { |i| + Dstutter(2, Dbufrd(Dswitch1(zeroXBufs, sndBufIndex[i]), zeroX[i] + xNum[i])); + }; + + // if dir = -1, base is second zero crossing + zeroXDiff = Dstutter(1, max((nextX - thisX / rate).abs.round), 2); + baseX = Dstutter(1, thisX * (1 + dir) + (nextX * (1 - dir)) / 2); + + sig = outSize.collect { |i| + overlapSize[i].collect { |j| + var localTrig, localZeroXDiff, localPhaseOffset, localRate, localDir, + localXRep, localOff, localGate, localGateDur, localPhase, localSndBufIndex, + localPower, localMul, localAdd, parBuf; + + localTrig = trig[i] * ((trigCount[i] % (overlapSize[i]) - DC.ar(j)).abs < 0.01); + + localZeroXDiff = Demand.ar(localTrig, 0, zeroXDiff[i]); + localPhaseOffset = Demand.ar(localTrig, 0, baseX[i]); + localRate = Demand.ar(localTrig, 0, rate[i]); + localDir = Demand.ar(localTrig, 0, dir[i]); + localXRep = xRep[i].isNumber.if { xRep[i] }{ Demand.ar(localTrig, 0, xRep[i]) }; + + // gate for wavesets, workaround with Sweep because of Trig1 init issue + localGateDur = localXRep * localZeroXDiff * SampleDur.ir; + localGate = Sweep.ar(localTrig) < localGateDur; + + // the combination of localGate and Sweep + modulo implements repetitions + localPhase = Sweep.ar( + localTrig, + SampleRate.ir * localRate + ) % (localZeroXDiff * localRate) * localDir.sign + localPhaseOffset; + + localSndBufIndex = Demand.ar(localTrig, 0, sndBufIndex[i]); + + localPower = power[i].isNumber.if { power[i] }{ Demand.ar(localTrig, 0, power[i]) }; + localMul = mul[i].isNumber.if { mul[i] }{ Demand.ar(localTrig, 0, mul[i]) }; + localAdd = add[i].isNumber.if { add[i] }{ Demand.ar(localTrig, 0, add[i]) }; + + bufMix[i].isNumber.if { + BufRd.ar(1, sndBufs[bufMix[i]], localPhase, 0, interpl[bufMix[i]]) + }{ + // in case of switched buffers we must select from all buffer readers + // (BufRd doesn't allow ar buffer switching) + parBuf = bufSize.collect { |k| BufRd.ar(1, sndBufs[k], localPhase, 0, interpl[k]) }; + Select.ar(localSndBufIndex, parBuf) + } ** localPower * localMul + localAdd * localGate; + }.sum + } * env; + + ^sig.unbubble + } + +} + + ++Object { + miSC_Dmultiply2 { ^this } +} + ++Function { + miSC_Dmultiply2 { |n| ^this ! n } +} + ++SequenceableCollection { + miSC_Dmultiply2 { |n| ^{ |i| this.wrapAt(i) } ! n } +} diff --git a/Classes/ZeroX/ZeroXBufRd.sc b/Classes/ZeroX/ZeroXBufRd.sc new file mode 100644 index 0000000..eddff94 --- /dev/null +++ b/Classes/ZeroX/ZeroXBufRd.sc @@ -0,0 +1,225 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +AbstractZeroXBufRd : UGen { + + *checkBufMix { |bufMix, bufSize| + var outSize; + bufMix.isNil.if { + bufMix = (0..bufSize-1); + outSize = bufSize; + }{ + bufMix.isKindOf(SequenceableCollection).if { + outSize = bufMix.size + }{ + outSize = 1; + bufMix = bufMix.asArray + } + }; + ^[bufMix, outSize] + } + + *unbubbleInputIfNecessary { |... argList| + ^argList.collect { |item| + ((item.isKindOf(SequenceableCollection)) and: { item.size == 1 }).if { + item[0] + }{ + item + }; + } + } + + // restrict to possible drate arguments + *checkForWrongDrateInput { |maxArgSize ... args| + + if ((maxArgSize > 1) and: { + args.any { |x| + x.isKindOf(DUGen) or: { + x.isKindOf(SequenceableCollection) and: { + // do deep check, but only for DUGens + (x.size < maxArgSize) and: { x.flat.any { |y| y.isKindOf(DUGen) } } + } + } + } + }) { + SimpleInitError("For multichannel expansion demand rate " ++ + "ugens, that are needed more than once, have to be " ++ + "wrapped into Functions, see help file" + ).class_(this).throw + }; + } + + *dUniquifyIfNecessary { |item, dUniqueBufSize| + ^case + { item.isKindOf(DUGen) }{ Dunique(item, dUniqueBufSize) } + { item.isKindOf(UGen) }{ item } + { true }{ Dstutter(inf, item) } + } +} + + +ZeroXBufRd : AbstractZeroXBufRd { + + *ar { |sndBuf, zeroXBuf, bufMix, zeroX = 0, power = 1, mul = 1, add = 0, rate = 1, rateMul = 1, dir = 1, + interpl = 4, dUniqueBufSize = 1048576, length = inf, maxTime = inf, att = 0, rel = 1, + curve = -4, doneAction = 0| + var thisX, nextX, baseX, sndBufIndex, phase, phaseTrig, phaseOffset, count, time, + zeroXDiff, rateSig, rateMulSig, dirSig, sndBufIndexSig, bufSize, zeroXBufSize, + outSize, args, sig, env, sndBufs, zeroXBufs; + + args = [ + zeroX, power, mul, add, rate, rateMul, dir, interpl, dUniqueBufSize, + length, maxTime, att, rel, curve, doneAction + ]; + + bufSize = (sndBuf.size == 0).if { 1 }{ sndBuf.size }; + zeroXBufSize = (zeroXBuf.size == 0).if { 1 }{ zeroXBuf.size }; + + (zeroXBufSize != bufSize).if { + SimpleInitError("sizes of sndBuf and zeroXBuf (single channel buffers!) must correspond") + .class_(ZeroXBufWr).throw + }; + + // if bufMix is undefined then outSize = bufSize + // else outSize is given by bufMix size + #bufMix, outSize = this.checkBufMix(bufMix, bufSize); + + // args might be passd as Function of drate ugens, then expand + #zeroX, power, mul, add, rate, rateMul, dir, interpl, dUniqueBufSize, + length, maxTime, att, rel, curve, doneAction = + this.unbubbleInputIfNecessary(*args); + this.checkForWrongDrateInput(outSize, zeroX, power, mul, rateMul, add, rate, dir); + #zeroX, power, mul, add, rate, rateMul, dir, interpl, dUniqueBufSize = + [zeroX, power, mul, add, rate, rateMul, dir, interpl, dUniqueBufSize] + .collect { |x| x.miSC_Dmultiply2(outSize) }; + + // need everything in outSize + mul = outSize.collect { |i| mul.miSC_maybeWrapAt(i) }; + add = outSize.collect { |i| add.miSC_maybeWrapAt(i) }; + power = outSize.collect { |i| power.miSC_maybeWrapAt(i) }; + + dUniqueBufSize = outSize.collect { |i| dUniqueBufSize.miSC_maybeWrapAt(i) }; + length = outSize.collect { |i| length.miSC_maybeWrapAt(i) }; + maxTime = outSize.collect { |i| maxTime.miSC_maybeWrapAt(i) }; + att = outSize.collect { |i| att.miSC_maybeWrapAt(i) }; + rel = outSize.collect { |i| rel.miSC_maybeWrapAt(i) }; + curve = outSize.collect { |i| curve.miSC_maybeWrapAt(i) }; + doneAction = outSize.collect { |i| doneAction.miSC_maybeWrapAt(i) }; + + // interpl always refers to sndBufs, not to bufMix size + interpl = bufSize.collect { |i| interpl.miSC_maybeWrapAt(i) }; + + // begin of the subtle part: + // drate ugens are polled more than once, + // if they are polled in sync we can "multiply" them with Dstutter + // otherwise we need Dunique, this is the case for rate and sndBufIndex (bufMix), + // which are polled again after the half waveset length for which they are needed + + rate = outSize.collect { |i| + var r = rate.miSC_maybeWrapAt(i); + this.dUniquifyIfNecessary(r, dUniqueBufSize[i]); + }; + rateMul = outSize.collect { |i| + var rMul = rateMul.miSC_maybeWrapAt(i); + this.dUniquifyIfNecessary(rMul, dUniqueBufSize[i]); + }; + dir = outSize.collect { |i| + var d = dir.miSC_maybeWrapAt(i); + this.dUniquifyIfNecessary(d, dUniqueBufSize[i]); + }; + + zeroXBufs = zeroXBuf.asArray; + sndBufs = sndBuf.asArray; + + // buffer switch option with bufMix + + sndBufIndex = bufMix.asArray.collect { |b, i| + this.dUniquifyIfNecessary(b, dUniqueBufSize[i]); + }; + + // determine distance between zero crossings + zeroX = outSize.collect { |i| Dstutter(2, zeroX.miSC_maybeWrapAt(i)) }; + + thisX = outSize.collect { |i| + Dstutter(2, Dbufrd(Dswitch1(zeroXBufs, sndBufIndex[i]), zeroX[i])) + }; + + nextX = outSize.collect { |i| + Dstutter(2, Dbufrd(Dswitch1(zeroXBufs, sndBufIndex[i]), zeroX[i] + 1)) + }; + + // if dir = -1, baseX is second zero crossing + baseX = Dstutter(1, thisX * (1 + dir) + (nextX * (1 - dir)) / 2); + // take half wavesets of minimum length 2, otherwise no trigger + zeroXDiff = Dstutter(1, max((nextX - thisX / (rate * rateMul)).abs.round, 2)); + + // trigger for syncing, add 1 to baseX as zero should trigger too ... + phaseTrig = TDuty.ar(SampleDur.ir * zeroXDiff, 0, baseX + 1); + // ... need value again, correct + phaseOffset = Latch.ar(phaseTrig - 1, phaseTrig); + + count = PulseCount.ar(phaseTrig); + time = Sweep.ar(Impulse.ar(0)); + + env = EnvGen.ar( + Env.asr(att, 1, rel, curve), + (count <= length) * (time <= maxTime), + doneAction: doneAction + ); + + // Demand doesn't multichannel expand + rateSig = phaseTrig.collect { |x, i| Demand.ar(x, 0, rate[i]) }; + rateMulSig = phaseTrig.collect { |x, i| Demand.ar(x, 0, rateMul[i]) }; + dirSig = phaseTrig.collect { |x, i| Demand.ar(x, 0, dir[i]) }; + + // phasor for waveset reading + phase = Sweep.ar( + phaseTrig, + SampleRate.ir * rateSig * rateMulSig * dirSig + ) + phaseOffset; + + power = power.collect { |p, i| p.isNumber.if { p }{ Demand.ar(phaseTrig[i], 0, p) } }; + mul = mul.collect { |m, i| m.isNumber.if { m }{ Demand.ar(phaseTrig[i], 0, m) } }; + add = add.collect { |a, i| a.isNumber.if { a }{ Demand.ar(phaseTrig[i], 0, a) } }; + + sndBufIndexSig = phaseTrig.collect { |x, i| Demand.ar(x, 0, sndBufIndex[i]) }; + + sig = outSize.collect { |i| + var parBuf; + bufMix[i].isNumber.if { + BufRd.ar(1, sndBufs[bufMix[i]], phase[i], 0, interpl[bufMix[i]]) + }{ + // in case of switched buffers we must select from all buffer readers + // (BufRd doesn't allow ar buffer switching) + parBuf = bufSize.collect { |j| BufRd.ar(1, sndBufs[j], phase[i], 0, interpl[j]) }; + Select.ar(sndBufIndexSig[i], parBuf) + } + }; + + sig = sig ** power.abs * mul + add * env; + ^sig.unbubble + } +} + diff --git a/Classes/ZeroX/ZeroXBufWr.sc b/Classes/ZeroX/ZeroXBufWr.sc new file mode 100644 index 0000000..50a5334 --- /dev/null +++ b/Classes/ZeroX/ZeroXBufWr.sc @@ -0,0 +1,155 @@ + +/* + This file is part of miSCellaneous, a program library for SuperCollider 3 + + Created: 2020-04-19, version 0.23 + Copyright (C) 2009-2020 Daniel Mayer + Email: daniel-mayer@email.de + URL: http://daniel-mayer.at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +ZeroXBufWr : UGen { + + *ar { |in, sndBuf, zeroXBuf, startWithZeroX = 0, adjustZeroXs = 0, doneAction = 0| + var size, bufSize, zeroXBufSize, signToggle, sampleCount, zeroX, zeroXCount, + sampleCountSteps, zeroXPositions, newZeroXs, heldZeroXs, write, out, gate, initTrig; + + size = in.size; + + bufSize = (sndBuf.size == 0).if { 1 }{ sndBuf.size }; + zeroXBufSize = (zeroXBuf.size == 0).if { 1 }{ zeroXBuf.size }; + + (zeroXBufSize != bufSize).if { + SimpleInitError("sizes of sndBuf and zeroXBuf (single channel buffers!) must correspond") + .class_(ZeroXBufWr).throw + }; + + (max(size, 1) != bufSize).if { + SimpleInitError("size of in must correpond to number of single channel buffers") + .class_(ZeroXBufWr).throw + }; + + // signToggle always starts with 1, makes it easier to handle all cases + initTrig = Impulse.ar(0); + signToggle = Select.ar( + Latch.ar(in > 0, initTrig), + [in <= 0, in > 0] + ); + + // need to start with index 0, thus '- 1' + sampleCount = Sweep.ar(0, SampleRate.ir) - 1; + + // zeroX indicates triggers for the counter: + // differentiate behaviour at start and later + // according to flags startWithZeroX and adjustZeroXs + + // adjustZeroXs = -1: indicate all zeroXs, dont't write sound buffer + // adjustZeroXs = 0: indicate all zeroXs, write sound buffer + // adjustZeroXs = 1: indicate all zeroXs, write sound buffer, set to 0 there + // adjustZeroXs = 2: indicate zeroXs with min distance of 2, set to 0 there + + sndBuf = sndBuf.asArray; + adjustZeroXs = adjustZeroXs.asArray; + + zeroX = sndBuf.collect { |buf, i| + var sig, sampleToggle, flag = adjustZeroXs.miSC_maybeWrapAt(i); + + sig = Select.ar( + sampleCount.sign, + [ + // with flag 1 always start with zeroX + DC.ar(startWithZeroX.miSC_maybeWrapAt(i)), + // slope of signToggle indicates zeroX, if not at start + Slope.ar(signToggle.miSC_maybeWrapAt(i)).abs + ] + ) > 0; + + (flag == 2).if { + // take zeroXs with minimum distance 2 + sampleToggle = Duty.ar(SampleDur.ir, sig, Dseq([1, 0], inf)); + sig = sig * sampleToggle + }; + + sig + }; + + // workaround due to a Integrator init bug + zeroXCount = Integrator.ar( + Select.ar( + sampleCount.sign, + [DC.ar(0), zeroX] + ) + ) + Latch.ar(zeroX, initTrig); + zeroXCount = zeroXCount.asArray - 1; + + newZeroXs = Select.ar( + zeroX, + [DC.ar(0), sampleCount] + ).asArray; + + // if zeroXCount doesn't increase, the position shouldn't either: + // BufWr overwrites the same buffer position with the same value + + // 1 - zeroX is a trigger for start of same sign + heldZeroXs = Latch.ar(Delay1.ar(newZeroXs), 1 - zeroX).asArray; + + zeroXPositions = Select.ar( + zeroX, + [heldZeroXs, sampleCount] + ).asArray; + + out = in; + in = in.asArray; + zeroXBuf = zeroXBuf.asArray; + + write = DC.ar(0); + sndBuf.do { |buf, i| + var flag = adjustZeroXs.miSC_maybeWrapAt(i); + + case + // dont't write sound buffer + { flag == -1 }{ } + + // write sound buffer from in signal + { flag == 0 }{ write = (BufWr.ar(in[i], buf, sampleCount, 0) 0 } }{ + // ignore garbage + ((zeroXArray[count] >= 0) and: { zeroXArray[count] < this.numFrames }).if { + this.set(zeroXArray[count], 0) + }; + lastZeroX = zeroXArray[count]; + count = count + 1; + }; + "zero setting messages sent".postln; + action.value(zeroXArray); + } + ) + } +} + + ++ SequenceableCollection { + adjustZeroXs { |zeroXBufs, action| + this.do { |buf, i| buf.adjustZeroXs(zeroXBufs[i], action.miSC_maybeWrapAt(i)) } + } +} + + + \ No newline at end of file diff --git a/Help/Buffer Granulation.html b/Help/Buffer Granulation.html new file mode 100755 index 0000000..1d243f6 --- /dev/null +++ b/Help/Buffer Granulation.html @@ -0,0 +1,1714 @@ + + + + + + + + + + + +

Buffer Granulation different approaches to buffer granulation with gui examples

+


+

Part of: miSCellaneous

+


+

See also: Live Granulation, Introduction to miSCellaneous, VarGui, VarGui shortcut builds, PLx suite, PbindFx, kitchen studies, Sieves and Psieve patterns, PSPdiv, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

As with many things in SC work can be done by language or server. Speaking about granulation in general this mainly concerns the control of single grains, their rate, timing, length and other parameters. Regarding buffer granulation specifically this task can e.g. be taken over by ugens like TGrains and GrainBuf, the latter additionally accepting a grain envelope arg. The SC plugin distribution contains further variations (see BhobUGens, JoshUGens). By using granulation ugens in a SynthDef granular textures can be produced with a single Synth, including grain parameter sequencing with demand rate ugens, the DX suite opens additional genuine options in this regard. Alternatively SynthDefs for single grains can be defined with PlayBuf or BufRd in order to control the whole buffer granulation process from language side, using Patterns, Tasks or Routines. What is the best way? To a large extent this is a question of personal preference. Regarding CPU performance granulation ugens have an advantage, whereas e.g. pattern-driven granulation allows concise control over the sequencing of granulation parameters in a clear syntax. If pattern-driven granulation is becoming CPU-critical you might want to consider the event type \grain, a lightweight variant of default type \note (see comment in the source file Event.sc). For granulation with Tasks see example 3 in VarGui.  

+


+

Also hybrid strategies are possible, e.g. language controlled setting of a single granulation Synth or involving extra control synths in a language-driven granulation process, further options are Pspawner / Pspawn and Wavesets. VarGui can be used to integrate these setups in single GUIs. Together with this file (miSCellaneous v0.7) I reinvented a color grouping option that overrides automatic color grouping (VarGui, Ex. 7). The latter is based on the logical structure of ordinary and array controls, synths and environments. This is useful for VarGuis up to a medium number of controls per Synth / Pattern / Task and also for a large number of such items, but it doesn't handle cases well where there are many controls per item. Not barely an aesthetic detail, it is much more convenient for experimenting to group all sliders of a Synth that, say, have to do with a bandpass filter, within one color. 

+


+

Types of variables

+


+

In general interpreter variables are prefered in examples below, wherever possible. If evaluated with example code only their values are passed and further changing of used variables doesn't affect already generated gui instances. On the contrary repeated evaluation of an interpreter variable, e.g. from a Pfunc, is unsafe - variable's value could change while gui has not yet been closed - so in concerned examples values are passed to the event definition, in Ex. 2c a variable is declared for the same reason. 

+

The use of environmental variables is following the way VarGui is handling them. Per default every EventStreamPlayer derived from a passed Pattern is run in a separate newly generated Environment, where variables are being set and Streams from Pfuncs and PLx patterns are reading from. See Event patterns and Functions, PLx suite and VarGui.

+


+


+

WARNING: 

+


+

1.) Be careful with amplitudes, especially with buffers you haven't granulated before !

+

Also keep in mind that a granular cloud moving through a buffer can suddenly become louder and other controls than amp (e.g. buffer position, trigger rate, bandpass parameters) can cause a raise of amplitude too.

+


+

2.) I haven't used below setups for live performances. Although all of them work stable for me as they are, in general hangs can occasionally happen with pattern-driven setups. Often this can be tracked down to sequences of extremely short event durations (and/or long grain durations). Where this can happen as a side-effect, thresholds can be built in, e.g. example 2d (Wavesets) has a parameter maxTrigRate. 

+

Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended - and if more complications are involved: testing without sound first, after saving your patch, might be a good idea.

+


+


+

NOTE: 

+


+

All variants from this tutorial can be applied to a buffer, which is occasionally (or continuously) filled with live input. Vice versa variants from Live Granulation can of course be applied to any signal, thus also to any playback of a buffer. 

+


+

All examples below expect mono buffers. Buffer paths refering to the included sample suppose that you have installed via quarks or moved miSCellaneous lib into the user or system extensions directory directly (not into a subfolder), if not so or you have moved the sample file somewhere else you'd have to change paths accordingly.

+


+

Due to a bug in SC 3.7 / 3.8 TGrains didn't response to amp changes, I changed the examples accordingly, the bug is fixed in 3.9.

+


+

Windows 7:  While other parts of miSCellaneous lib were running fine I was unable to allocate buffers with the SC 3.5.4 Windows binary in August 2012. Meanwhile this issue has been solved (SC 3.6.6, February 2014). There also seemed to be accuracy issues with OffsetOut on Windows with SC 3.6 still, but not with newer versions.

+


+

+

Credits 

+


+

Thanks for contributions and inspirations by SCers Alberto de Campo (Wavesets), James Harkins (Patterns), Ron Kuivila (Pspawner), Sergio Luque (stochastic distributions), Josh Parmenter (granulation plugins), Bhob Rainey (granulation plugins).

+


+


+

References

+


+

[1] de Campo, Alberto. "Microsound" In: Wilson, S., Cottle, D. and Collins, N. (eds). 2011. 

+

The SuperCollider Book. Cambridge, MA: MIT Press, 463-504.

+

+

[2] Luque, Sergio (2006). Stochastic Synthesis, Origins and Extensions. Institute of Sonology, Royal Conservatory, The Netherlands. 

+

http://sergioluque.com

+


+

[3] Roads, Curtis (2001). Microsound. Cambridge, MA: MIT Press.

+

+

[4] Wishart, Trevor (1994). Audible Design. York: Orpheus The Pantomime Ltd. 

+


+

[5] Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition.

+


+


+

+

1.) Granulation with Ugens

+


+

Example 1a:   Basic buffer granulation Synth

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// basic SynthDef suited for pitch-shift and time-stretch

+

// buffer position given relatively (posLo and posHi between 0 and 1)

+

// posDev: maximum amount of deviation from (moving) grain center position

+

// posDev = 0 can lead to comb filter effects (which may be nice sometimes)

+


+

// passing control specs as metadata allows for VarGui shortcut build method sVarGui

+

// metadata specs can be overwritten by arg ctrReplace

+

// alternatively control specs may be passed as synthCtr arg to a build with VarGui( ... )

+


+

(

+

SynthDef(\gran_1a, { arg out = 0, bufNum = 0, posLo = 0.0, posHi = 1.0, 

+

posRate = 1, posDev = 0.01, trigRate = 100, granDur = 0.1, rate = 1.0, 

+

panMax = 1, amp = 0.1, interp = 4;

+

+

var trig, pan, pos, bufDur, bufDurSection, posDif;

+

+

posDif = posHi - posLo;

+

bufDur = BufDur.kr(bufNum);

+

bufDurSection = bufDur * posDif;

+

trig = Impulse.kr(trigRate);

+

pos = posLo * bufDur +

+

(Phasor.ar(0, BufRateScale.kr(bufNum) * posRate / SampleRate.ir, posLo * bufDur, posHi * bufDur) + 

+

(TRand.kr(-0.5 * posDev, 0.5 * posDev, trig) * bufDur)).mod(bufDurSection);  

+

pan = Demand.kr(trig, 0, Dseq([panMax, panMax.neg],inf) * 0.999);

+

Out.ar(out, TGrains.ar(2, trig, bufNum, rate, pos, granDur, pan, 1, interp) * amp);

+

}, metadata: (

+

specs: (

+

posLo: [0.01, 0.99, \lin, 0.01, 0],

+

posHi: [0.01, 0.99, \lin, 0.01, 1],

+

posRate: [0.1, 2, \lin, 0.01, 1],

+

posDev: [0, 0.2, 5, 0, 0.01],

+

granDur: [0.01, 0.3, \lin, 0.01, 0.1],

+

trigRate: [1, 200, \lin, 0.01, 100], 

+

rate: [0.1, 2, \lin, 0.01, 1],

+

panMax: [0.0, 1, \lin, 0.005, 0.8],

+

amp: [0.0, 0.5, \lin, 0.005, 0.25]

+

)

+

)

+

).add;

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

)

+


+


+

// start from GUI

+


+

\gran_1a.sVarGui([\bufNum, b.bufnum]).gui;

+


+


+


+

Example 1b:   More deviations

+


+


+

// In example 1a only a deviation from the grain center position was implemented.

+

// With additional deviation controls a greater plasticity of sound can be achieved,

+

// here deviations are added for trigRate (LFO with oscillation freq and deviation max),

+

// grain duration and rate (TRand, equally weighted random deviation with given max).

+

// Deviations intervals could be defined alternatively, 

+

// e.g. (1/(1+maxDev), 1+maxDev) with 0 < maxDev

+

// instead of (1-maxDev, 1+mexDev) with 0 < maxDev < 1

+


+

// posRate control range is widened by inventing two controls for 

+

// mantissa and exponent, so posRate = 1 for init param pair 

+

// posRateE = 0 and posRateM = 1

+


+

(

+

SynthDef(\gran_1b, { arg out = 0, bufNum = 0, posLo = 0.0, posHi = 1.0, 

+

posRateE = 0, posRateM = 1, posDev = 0.01, trigRate = 100, trigRateDev = 0, 

+

trigRateOsc = 1, granDur = 0.1, granDurDev = 0, rate = 1.0, rateDev = 0, 

+

panMax = 1, amp = 0.1, interp = 4;

+

+

var trig, pan, pos, bufDur, bufDurSection, posDif, posRate;

+

+

posDif = posHi - posLo;

+

bufDur = BufDur.kr(bufNum);

+

bufDurSection = bufDur * posDif;

+

trig = Impulse.kr(LFDNoise3.kr(trigRateOsc, trigRate * trigRateDev, trigRate));

+

posRate = 10 ** posRateE * posRateM;

+

pos = posLo * bufDur +

+

(Phasor.ar(0, BufRateScale.kr(bufNum) * posRate / SampleRate.ir, posLo * bufDur, posHi * bufDur) + 

+

(TRand.kr(-0.5, 0.5, trig) * posDev * bufDur)).mod(bufDurSection);  

+

pan = Demand.kr(trig, 0, Dseq([panMax, panMax.neg],inf) * 0.999);

+

Out.ar(out, TGrains.ar(2, trig, bufNum, rate * (TRand.kr(-1, 1.0, trig) * rateDev + 1), pos, 

+

granDur * (TRand.kr(-1, 1.0, trig) * granDurDev + 1), pan, 1, interp) * amp);

+

}, metadata: (

+

specs: (

+

posLo: [0.01, 0.99, \lin, 0.01, 0],

+

posHi: [0.01, 0.99, \lin, 0.01, 1],

+

posRateE: [-3, 4, \lin, 1, 0],

+

posRateM: [0.1, 10, \exp, 0.01, 1],

+

posDev: [0, 0.2, 5, 0, 0.05],

+

trigRate: [1, 200, \lin, 0.01, 100], 

+

trigRateDev: [0.0, 1, \lin, 0.01, 0],

+

trigRateOsc: [0.1, 2, \lin, 0.01, 3],

+

granDur: [0.01, 0.3, \lin, 0.01, 0.1],

+

granDurDev: [0.0, 0.95, \lin, 0.01, 0],

+


+

rate: [0.1, 2, \lin, 0.01, 1],

+

rateDev: [0.0, 0.99, \linear, 0.01, 0.05],

+

panMax: [0.0, 1, \lin, 0.005, 0.8],

+

amp: [0.0, 0.5, \lin, 0.005, 0.25]

+

)

+

)

+

).add;

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

)

+


+


+

// start from GUI

+

// use color grouping for better overview

+


+

\gran_1b.sVarGui([\bufNum, b.bufnum]).gui(synthColorGroups: (0..14).clumps([1,5,3,2,2,1,1]) )

+


+


+


+

Example 1c:   Buffer granulation Synth with external control synths

+


+


+

// This is a more modular approach, once having a basic granulation synth

+

// it can be linked with arbitrary control synths, here

+

// also moving through the buffer is controlled externally.

+

// Depending on LFOs it might be worth defining 

+

// audio buses for control to get higher precision.

+


+


+

(

+

SynthDef(\gran_1c, { arg out = 0, bufNum = 0, amp = 0.1, pos = 0.5, posDev = 0.01, 

+

trigRate = 100, granDur = 0.1, rate = 1, panMax = 1, interp = 4;

+

var trig, pan;

+

trig = Impulse.kr(trigRate);

+

pan = Demand.kr(trig, 0, Dseq([panMax, panMax.neg],inf) * 0.999);

+

pos = (pos * BufDur.kr(bufNum) * WhiteNoise.kr(posDev, 1));

+

Out.ar(out, TGrains.ar(2, trig, bufNum, rate, pos, granDur, pan, 1, interp) * amp);

+

}).add;

+


+


+

// LFO synthdef for switching between 3 types: 

+

// 0: LFDNoise3 (smooth random movement)

+

// 1: SinOsc

+

// 2: LFSaw (works as phasor for position)

+


+

SynthDef(\lfo, { |out = 0, lfoType = 0, freq = 1, lo = 0, hi = 1| 

+

var ctrl;

+

ctrl = Select.kr(lfoType, [

+

LFDNoise3,

+

SinOsc,

+

LFSaw

+

].collect { |x| x.kr(freq, mul: hi-lo/2, add: hi+lo/2) });

+

    Out.kr(out, ctrl); 

+

}).add; 

+


+

// multichannel control bus 

+

c = Bus.control(s, 5);

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

)

+


+


+

// In contrast to Ex. 1a and 1b VarGui is called explicitely

+

// as control specs should differ.

+


+

// Also here the granulation Synth is generated explicitely and not by the interface

+

// as its controls have to be mapped to buses

+


+

(

+

// start granulation synth paused and register

+

// to let VarGui know its state

+


+

x = Synth.newPaused(\gran_1c, [\bufNum, b]).register;

+


+

// map args to be controlled to consecutive subbuses

+

x.map(*[[\pos, \trigRate, \granDur, \rate, \panMax], (0..4).collect(c.subBus(_))].flop.flat)

+

)

+


+

(

+

// Open VarGui interface, granulation synth (#5) is paused

+

// (orange button on yellow background).

+

// Shift-clicking one of the green buttons runs

+

// granulation synth and control synths (#0 - #4).

+

// All synths can be paused (orange button) and resumed.

+


+

// NOTE: When stopping the granulation synth 

+

// the linkage with control synths is lost! 

+

// A new synth generated by the interface 

+

// (by pressing the blue button of #5) is not

+

// automatically mapped to control buses.

+

// On the other hand control synths might be stopped and 

+

// newly generated.

+

 

+


+

VarGui(synthCtr: [[

+

\pos, 0, // dummy spec for labelling 

+

\out, c.index,

+

\lfoType, [0, 2, \lin, 1, 0], 

+

// as LFOs are unified, original movement tempo is 

+

// indicated not by 1 but by 1 / buffer duration

+

\freq, [0.01, 20, \exp, 0.0, 1/b.duration],

+

\lo, [0.0, 1, \lin, 0, 0.1],

+

\hi, [0.0, 1, \lin, 0, 0.9]

+

],[

+

\trigRate, 1,

+

\out, c.index + 1,

+

\lfoType, [0, 2, \lin, 1, 0], 

+

\freq, [0.001, 0.5, \exp, 0.0, 0.2],

+

\lo, [1, 100, \lin, 0, 7],

+

\hi, [1, 100, \lin, 0, 40]

+

],[

+

\granDur, 2,

+

\out, c.index + 2,

+

\lfoType, [0, 2, \lin, 1, 1], 

+

\freq, [0.001, 0.5, \exp, 0.0, 0.4],

+

\lo, [0.01, 0.2, \lin, 0, 0.1],

+

\hi, [0.01, 0.2, \lin, 0, 0.15]

+

],[

+

\rate, 3,

+

\out, c.index + 3,

+

\lfoType, [0, 2, \lin, 1, 0], 

+

\freq, [0.001, 0.1, \exp, 0.0, 0.03],

+

\lo, [0.1, 3, \lin, 0, 0.6],

+

\hi, [0.1, 3, \lin, 0, 1.1]

+

],[

+

\panMax, 4,

+

\out, c.index + 4,

+

\lfoType, [0, 2, \lin, 1, 0], 

+

\freq, [0.001, 0.5, \exp, 0.0, 0.5],

+

\lo, [0.0, 1, \lin, 0, 0.06],

+

\hi, [0.0, 1, \lin, 0, 0.9]

+

],[

+

\out, 0,

+

\bufNum, b.bufnum,

+

  \posDev, [0.001, 0.2, \exp, 0, 0.02],

+

  \amp, [0.0, 2, \lin, 0, 0.5]

+

]],

+

  // 5 lfo synths are generated by the interface (synthdef name passed)

+

// but granulation Synth is passed directly as object

+

synth: \lfo!5 ++ x

+

).gui(sliderPriority: \synth, playerPriority: \synth); 

+

)

+


+


+

Example 1d:   Buffer granulation Synth with demand rate ugens

+


+


+

// Repeated grain triggering within a synth can be defined by demand rate ugens, 

+

// which is comfortable in connection with granular ugens.

+


+

// E.g. with TGrains you can trigger parameters like grain duration, playback rate, 

+

// position, panning and amp, single grains will keep their params if they overlap.

+

// (Note that in the below implementation changes of demand rate array fields will apply

+

// also not before the next call of those fields in the synth)

+


+

// More refined per-grain control, e.g. per-grain filtering with filter parameter streams,

+

// can be done by using a multichannel trick, see Ex. 1e.

+


+

(

+

// length of demand rate sequence, you might want to check larger sizes

+

// in connection with gui arg tryColumnNum > 1

+

~n = 5;

+


+

// posRate control range is widened by inventing two controls for 

+

// mantissa and exponent, so posRate = 1 for init param pair 

+

// posRateE = 0 and posRateM = 1

+


+

SynthDef(\gran_1d, { |out = 0, soundBuf, posLo = 0.1, posHi = 0.3, 

+

posRateE = 0, posRateM = 1, granDurMul = 1, rateMul = 1, panMul = 1, amp = 0.5, interp = 2| 

+

+

var signal, bufDur, granDur, granGate, relGranDurs, pos, overlap, overlaps, overlapSeq, 

+

pan, rate, relRates, rateSeq, posRate, granDurSeq; 

+

+

// array args for demand rate sequencing, short form of NamedControl

+

relGranDurs = \relGranDurs.kr(0.1!~n);

+

relRates = \relRates.kr(1!~n); 

+

overlaps = \overlaps.kr(1!~n); 

+


+

// Dstutter (or Dunique) necessary as granDurSeq is polled twice: granGate and granDur

+

granDurSeq = Dstutter(2, Dseq(relGranDurs, inf));  

+

rateSeq = Dseq(relRates, inf); 

+

overlapSeq = Dseq(overlaps, inf); 

+

+

granGate = TDuty.ar(granDurSeq * granDurMul); 

+

granDur = Demand.ar(granGate, 0, granDurSeq * granDurMul);

+

rate = Demand.ar(granGate, 0, rateSeq) * rateMul; 

+

pan = Demand.ar(granGate, 0, Dseq([1, -1], inf)) * 0.999 * panMul; 

+

overlap = Demand.ar(granGate, 0, overlapSeq);

+


+

bufDur = BufDur.kr(soundBuf);

+

posRate = 10 ** posRateE * posRateM;

+


+

pos = Phasor.ar(0, BufRateScale.kr(soundBuf) * posRate / (SampleRate.ir * bufDur), posLo, posHi);

+

signal = TGrains.ar(2, granGate, soundBuf, rate, pos * bufDur, granDur * overlap, pan, 1, interp);

+

+

Out.ar(out, signal * amp); 

+

}

+

).add; 

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

)

+


+

(

+

// relGranDurs are multiplied with granDurMul, analogously relRates with rateMul.

+

// Changes of these params apply immediately in contrast to the array args 

+

// used by demand rate ugens which are used with next demand.

+


+

// check out moving a number of sliders of one array by using

+

// Shift, Alt + Shift and Ctrl + Shift, see VarGui help Ex. 1c.

+

 

+


+

VarGui(synthCtr: [

+

soundBuf: b.bufnum,

+

+

posLo: [0, 1, \lin, 0, 0.1],

+

posHi: [0, 1, \lin, 0, 0.9],

+

posRateE: [-3, 4, \lin, -1, 0],

+

posRateM: [0.1, 10, \exp, 0.01, 0.5],

+


+

// generating control specifications depending on index

+

relGranDurs: { |i| [0.01, 0.1, \lin, 0, i * 0.005 + 0.02] } ! ~n,

+

granDurMul: [0.03, 2, \lin, 0, 0.25],

+

overlaps: [0.1, 5, \lin, 0, 1.5] ! ~n,

+

+

relRates: { |i| [0.1, 1.5, \lin, 0, (5-i) * 0.1 + 0.5] } ! ~n,

+

rateMul: [0.1, 2, \lin, 0, 0.5],

+

+

panMul: [0, 1, \lin, 0, 0.6],

+

amp: [0.0, 3, \lin, 0, 2]

+

],

+

synth: \gran_1d

+

).gui(

+

tryColumnNum: 1,

+

// color grouping for better overview

+

synthColorGroups: (0..(~n*3+8)).clumps([1,4,~n+1,~n,~n+1,1,1]), 

+

labelWidth: 90,

+

sliderWidth: 280 

+

);

+

)

+


+


+


+

Example 1e:   Buffer granulation Synth with per-grain effect processing (TGrains)

+


+


+

// TGrains and other granular ugens allow per-grain processing

+

// for a limited number of parameters (pos, rate etc.)

+

// Nevertheless it is possible to apply arbitrary effects with

+

// per-grain parameter changes, even if grains overlap.

+

// This can be achieved by defining the granulation output

+

// as a multichannel signal and appropriate triggering of fx parameters.

+

// The example is adapted from a recommendation of Julian Rohrhuber.

+


+

// The method is elegant but also a bit tricky in terms of

+

// multichannel triggering and channel routing.

+


+

(

+

// the multichannel size and equivalently:

+

// the maximum number of overlapping grains that might get

+

// different fx parameters have to be fixed.

+

// For convenience of later L/R-spatialization we take an 

+

// even number ~n = 2 * ~m

+


+

~m = 5; 

+

~n = 2 * ~m; 

+


+

SynthDef(\gran_1e, { |out = 0, soundBuf, posLo = 0.1, posHi = 0.9, 

+

posRateE = 0, posRateM = 1, rate = 1, panMax = 0.8, bpRQ = 0.1, bpLo = 50, bpHi = 5000,

+

amp = 1, bpFund = 100, overlap = 2, trigRate = 1, interp = 2| 

+

var sig, sigL, sigR, bpFreq, chan, bpFreqSeqs, dUgen,

+

trig, trigs, bufDur, pos, posRate; 

+

+

trig = Impulse.ar(trigRate);

+

// we need a multichannel trigger that steps through all consecutive channels

+

trigs = { |i| PulseDivider.ar(trig, ~n, ~n-1-i) } ! ~n; 

+


+

chan = Demand.ar(trig, 0, Dseq((0..~n-1), inf)); 

+

+

posRate = 10 ** posRateE * posRateM;

+

bufDur = BufDur.kr(soundBuf);

+

pos = Phasor.ar(0, BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, posLo, posHi);

+

+

sig = TGrains.ar(~n, trig, soundBuf, rate, pos * bufDur, overlap/trigRate, 

+

// Panning convention is that from PanAz,

+

// speakers should be from 0 to 2, but (orientation)

+

// 1/n has to be substracted for n speakers.

+

// If this isn't done correctly grains are spread onto more than one channel

+

// and per-grain application of fxs fails.

+

chan.linlin(0, ~n-1, -1/~n, (2*~n - 3)/~n), 1, interp);

+


+

dUgen = Dwhite(0.0, 1);

+

sig = sig.collect { |ch, i| 

+

// this is the place to define fxs per channel/grain

+

// multichannel trigger is polling from a single demand ugen

+

bpFreq = Demand.ar(trigs[i], 0, dUgen).linlin(0, 1, bpLo, bpHi); 

+

+

// amplitude compensation for lower rq of bandpass filter

+

BPF.ar(ch, bpFreq, bpRQ, (bpRQ ** -1) * (400 / bpFreq ** 0.5)); 

+

};

+

+

// routing to two channels ...

+

sigL = Mix(((0..(~m-1)) * 2).collect(sig[_])); 

+

sigR = Mix(((0..(~m-1)) * 2 + 1).collect(sig[_])); 

+

+

// ... in order to have L/R-spreading with panMax as in other examples

+

Out.ar(0, Pan2.ar(sigL, panMax.neg) + Pan2.ar(sigR, panMax) * amp) 

+

}).add;

+


+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

) 

+


+


+

(

+

VarGui(synthCtr: [

+

soundBuf: b.bufnum,

+

posLo: [0, 1, \lin, 0, 0.2],

+

posHi: [0, 1, \lin, 0, 0.5],

+

posRateE: [-3, 4, \lin, -1, -1],

+

posRateM: [0.1, 10, \exp, 0.01, 0.8],

+

overlap: [0.1, ~n, \lin, 0, 12],

+

trigRate: [1, 100, \lin, 0, 45],

+

rate: [0.1, 2, \lin, 0, 1],

+

+

bpRQ: [0.05, 1, \lin, 0, 0.25],

+

bpLo: [50.0, 5000, \exp, 0, 50],

+

bpHi: [50.0, 5000, \exp, 0, 5000],

+

panMax: [0, 1, \lin, 0, 0.85],

+

amp: [0.0, 3, \lin, 0, 1]

+

],

+

synth: \gran_1e

+

).gui(

+

tryColumnNum: 1,

+

synthColorGroups: (0..12).clumps([1,4,2,1,3,1,1]) 

+

);

+

)

+


+


+


+

Example 1f:   Buffer granulation Synth with per-grain effect processing (DXEnvFan)

+


+


+

// DXEnvFan generates a multichannel envelope which can be used as trigger for granulation and fxs on grains.

+

// It encapsulates the trigger logic, which has been used explicitely in Ex. 1e.

+

// DX ugens can be used for a variety of microsound techniques, see their help files.

+


+

(

+

~maxOverlap = 12;

+

a = Bus.audio(s, ~maxOverlap);

+


+

// overlap only settable in SC versions >= 3.9

+


+

SynthDef(\gran_1f, { |out = 0, soundBuf, bus = 0, posLo = 0.1, posHi = 0.9,

+

    posRateE = 0, posRateM = 1, overlap = 2, trigRate = 1, rate = 1, 

+

bpRQ = 0.1, bpLo = 50, bpHi = 5000, panMax = 0.8, amp = 1|

+

    var sig, bpFreq, dUgen, bufDur, pos, posRate, playbuf, env, maxOverlap = ~maxOverlap;

+


+

    posRate = 10 ** posRateE * posRateM;

+

    bufDur = BufDur.kr(soundBuf);

+

    pos = Phasor.ar(0, BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, posLo, posHi);

+


+

    // multichannel trigger

+

    env = DXEnvFan.ar(

+

        Dseq((0..maxOverlap-1), inf),

+

        trigRate.reciprocal,

+

        size: maxOverlap,

+

        maxWidth: maxOverlap,

+

        width: (Main.versionAtLeast(3, 9)).if { overlap }{ 2 },

+

        // option to avoid unwanted triggers

+

        zeroThr: 0.002,

+

        // take equalPower = 0 for non-squared sine envelopes

+

        // more efficient with helper bus

+

        equalPower: 0,

+

        bus: a

+

    );

+

    // multichannel playback, pos is triggered for each grain

+

    playbuf = PlayBuf.ar(1, soundBuf, rate, env, pos * BufFrames.ir(soundBuf), 1);

+


+

    dUgen = Dwhite(0, 1);

+

    // multichannel trigger used to poll values from drate ugen

+

    bpFreq = Demand.ar(env, 0, dUgen).linlin(0, 1, bpLo, bpHi);

+


+

    // generate grains by multiplying with envelope

+

    sig = playbuf * env;

+


+

    // different frequency on each grain channel

+

    sig = BPF.ar(sig, bpFreq, bpRQ, (bpRQ ** -1) * (400 / bpFreq ** 0.5));

+


+

    // generate array of 5 stereo signals

+

    sig = Pan2.ar(sig, Demand.ar(env, 0, Dseq([-1, 1], inf) * panMax));

+


+

    // mix to out

+

    Out.ar(0, Mix(sig) * amp)

+

}, metadata: (

+

    specs: (

+

        posLo: [0.01, 0.99, \lin, 0.01, 0],

+

        posHi: [0.01, 0.99, \lin, 0.01, 0.5],

+

        posRateE: [-3, 4, \lin, 1, -1],

+

        posRateM: [0.1, 10, \exp, 0.01, 1.35],

+

        trigRate: [1, 200, \lin, 0.01, 90],

+

        overlap: [0.2, 12, \lin, 0.01, 7],

+

        rate: [0.1, 2, \lin, 0.01, 0.75],

+

        panMax: [0.0, 1, \lin, 0.005, 0.75],

+

        bpLo: [100, 5000, \lin, 0, 300],

+

        bpHi: [100, 5000, \lin, 0, 3000],

+

        bpRQ: [0.05, 1, \lin, 0, 0.18],

+

        amp: [0.0, 3, \lin, 0.005, 1]

+

    )

+

)).add;

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

)

+


+

(

+

\gran_1f.sVarGui([\soundBuf, b.bufnum]).gui(

+

    tryColumnNum: 1,

+

    synthColorGroups: (0..12).clumps([1,4,2,1,3,1,1])

+

)

+

)

+


+

Example 1g: Buffer granulation with (half) wavesets: ZeroXBufRd

+


+

// movement through the buffer of zero crossings

+

// with a slow pos rate we get repetitions of half wavesets

+


+

// load sound buffer

+


+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+


+

// allocate zeroX buffer

+


+

(

+

z = Buffer.alloc(s, b.duration * 44100 / 5, 1);

+

s.scope;

+

)

+


+


+

// write zero crossings, but no need to overwrite sound buffer

+

// this is caused by setting adjustZeroXs to -1

+


+

(

+

{

+

// use LeakDC to avoid extremely long half wavesets

+

var src = LeakDC.ar(PlayBuf.ar(1, b, BufRateScale.ir(b)));

+

ZeroXBufWr.ar(src, b, z, adjustZeroXs: -1, doneAction: 2);

+

}.play

+

)

+


+


+

// instead adjust from lang and get zeroXs

+


+

b.adjustZeroXs(z, { |z| ~zeroXs = z.reject(_==0) })

+


+

// get number of zeroXs

+


+

~zeroXNum = ~zeroXs.size

+


+


+

(

+

SynthDef(\gran_1g, { |out = 0, soundBuf, zeroXBuf, zeroXNum, posLo = 0.1, posHi = 0.9,

+

    posRateE = 0, posRateM = 1, rate = 1, amp = 1|

+

    var sig, bufDur, pos, posRate;

+


+

    posRate = 10 ** posRateE * posRateM;

+

bufDur = BufDur.kr(soundBuf);

+


+

// move through the buffer of zero crossings

+

// the tempo (rate) refers to the sound buffer

+

pos = Phasor.ar(

+

0,

+

BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur,

+

posLo,

+

posHi

+

) * zeroXNum;

+


+

sig = ZeroXBufRd.ar(

+

soundBuf,

+

zeroXBuf,

+

0!2,

+

pos,

+

mul: amp,

+

rate: rate * [1, 1.01]

+

     );

+

     Out.ar(0, sig * amp)

+

}, metadata: (

+

    specs: (

+

        posLo: [0.01, 0.99, \lin, 0.01, 0.1],

+

        posHi: [0.01, 0.99, \lin, 0.01, 0.5],

+

        posRateE: [-2, 2, \lin, 1, -1],

+

        posRateM: [0.1, 10, \exp, 0.01, 3],

+

        rate: [0.3, 3, \lin, 0.01, 1],

+

        amp: [0.0, 2, \lin, 0.005, 1]

+

)

+

)

+

).add;

+


+

\gran_1g.sVarGui([\soundBuf, b.bufnum, \zeroXBuf, z.bufnum, \zeroXNum, ~zeroXNum]).gui

+

)

+


+


+

Example 1h: Buffer granulation with (half) wavesets: TZeroXBufRd

+


+

// buffer preparations from Ex. 1g

+


+

// again a movement through the buffer of zero crossings is implemented

+

// the repetition of wavesets though is defined by xNum and xRep

+


+

// with high trigger rates, xNum and xRep values and low rates you might

+

// have to increase overlapSize, see TZeroXBufRd help for a discussion of this topic

+


+

(

+

SynthDef(\gran_1h, { |out = 0, soundBuf, zeroXBuf, zeroXNum, posLo = 0.1, posHi = 0.9,

+

    posRateE = 0, posRateM = 1, xNum = 1, xRep = 1, rate = 1, trigRate = 100, amp = 1|

+

    var sig, bufDur, pos, posRate;

+


+

    posRate = 10 ** posRateE * posRateM;

+


+

bufDur = BufDur.kr(soundBuf);

+

pos = Phasor.ar(

+

0, 

+

BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, 

+

posLo, 

+

posHi

+

) * zeroXNum;

+


+

// move through the buffer of zero crossings

+

// the tempo (rate) refers to the sound buffer

+

sig = TZeroXBufRd.ar(

+

soundBuf,

+

zeroXBuf,

+

0!2, // bufMix arg triggers stereo

+

trig: Impulse.ar(trigRate),

+

zeroX: pos,

+

xNum: xNum,

+

xRep: xRep,

+

mul: amp,

+

rate: rate * [1, 1.01], // a bit of decorrelation 

+

overlapSize: 20 // larger overlapSize

+

     );

+

// by overlapping a DC can easily accumulate, so do leak

+

Out.ar(0, LeakDC.ar(sig) * amp)

+

}, metadata: (

+

specs: (

+

posLo: [0.01, 0.99, \lin, 0.01, 0.1],

+

posHi: [0.01, 0.99, \lin, 0.01, 0.5],

+

posRateE: [-2, 2, \lin, 1, -1],

+

posRateM: [0.1, 10, \exp, 0.01, 1],

+

rate: [0.3, 2, \lin, 0.01, 1],

+

trigRate: [5, 120, \lin, 0, 50],

+

xNum: [1, 5, \lin, 1, 2],

+

xRep: [1, 5, \lin, 1, 3],

+

amp: [0.0, 2, \lin, 0, 1]

+

)

+

)

+

).add;

+


+

\gran_1h.sVarGui([\soundBuf, b.bufnum, \zeroXBuf, z.bufnum, \zeroXNum, ~zeroXNum]).gui

+

)

+


+


+

2.) Granulation driven by language

+


+


+

NOTE: 

+


+

Language-driven sequencing is not sample-exact in realtime (with NRT synthesis it is). This is related to hardware control and cannot be overcome currently. However for most practical purposes this might not be relevant. It is anyway a far less strong effect than the inaccuracies related to Out.ar and the combination of OffsetOut.ar and In.ar (see examples 2a-d in Live Granulation)

+


+


+

Example 2a:   Basic buffer granulation Pbind

+


+


+

// Control parameters like in 1a, but implemented with a SynthDef for

+

// playing single grains and an appropriate Pbind,

+

// OffsetOut used for exact timing.

+


+

(

+

SynthDef(\gran_2a, { |out = 0, pos = 0, sndBuf = 0, windowBuf = 1, granDur = 0.1, 

+

rate = 1, loop = 1, panMax = 0, amp = 1| 

+

var window, src;

+

src = PlayBuf.ar(1, sndBuf, BufRateScale.kr(sndBuf) * rate, 

+

1, round(pos * BufFrames.kr(sndBuf)), loop, 2);

+

window = BufRd.ar(1, windowBuf, 

+

EnvGen.ar(Env([0, BufFrames.kr(windowBuf)], [granDur]), 

+

doneAction: 2), loop, 4); 

+

OffsetOut.ar(out, Pan2.ar(src, panMax, amp) * window); 

+

}).add; 

+


+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

w = Buffer.sendCollection(s, Signal.hanningWindow(1024));

+

)

+


+


+

// Determining the correct buffer position depending on

+

// posRate, posLo and posHi needs a little calculation.

+

// In 1a this was done inside the ugen by a Phasor.

+

// See Ex. 3b, 3c for doing position movement with a separate Synth.

+


+

// PL placeholder patterns used, could also be Pfunc { ~ ... }

+


+

(

+

p = Pbind( 

+

\instrument, \gran_2a, 

+

\sndBuf, b,

+

\windowBuf, w, 

+

+

\dur, 1 / PL(\trigRate), 

+

\granDur, PL(\granDur), 

+

\time, Ptime(),

+

\pos, Pfunc { |e|

+

var relTime = ~posRate * e.time / e.sndBuf.duration, relDif;

+

relDif = ~posHi - ~posLo;

+

relTime + rand2(~posDev) % relDif + ~posLo;

+

},

+

\rate, PL(\rate),  

+

\amp, PL(\amp),

+

\panMax, PLseq([-1,1]) * PL(\panMax),

+

\out, 0

+

);

+


+

VarGui([

+

\posLo, [0.0, 0.99, \lin, 0.01, 0],

+

\posHi, [0.0, 0.99, \lin, 0.01, 1],

+

\posRate, [0.1, 2, \lin, 0.01, 1],

+

\posDev, [0, 0.2, 5, 0, 0.01],

+

\trigRate, [1, 200, \lin, 0.01, 120],

+

\granDur, [0.01, 0.3, \lin, 0.005, 0.06], 

+

\rate, [0.1, 3, \lin, 0.01, 1],

+

\panMax, [0.0, 1, \lin, 0.0, 0.8],

+

\amp, [0.0, 1, \lin, 0.01, 0.25]

+

], stream: p

+

).gui(varColorGroups: (0..8).clumps([4,1,1,1,1,1]))

+

)

+


+


+


+

Example 2b:   Switching between stochastic distributions

+


+


+

// Extended basic SynthDef from Ex.2a with bandpass filter

+


+

(

+

SynthDef(\gran_2b, { |out = 0, pos = 0, sndBuf = 0, windowBuf = 1, granDur = 0.1, 

+

rate = 1, loop = 1, panMax = 0, amp = 1, bpFreq = 500, bpRQ = 0.5, bpWet = 1| 

+

var window, granSrc, src;

+

granSrc = PlayBuf.ar(1, sndBuf, BufRateScale.kr(sndBuf) * rate, 

+

1, round(pos * BufFrames.kr(sndBuf)), loop, 2);

+

window = BufRd.ar(1, windowBuf, 

+

EnvGen.ar(Env([0, BufFrames.kr(windowBuf)], [granDur]), 

+

doneAction: 2), loop, 4);

+

// do amplitude compensation, estimation like in Wavesets example by Alberto de Campo 

+

src = (BPF.ar(granSrc, bpFreq, bpRQ, mul: (bpRQ ** -1) * (400 / bpFreq ** 0.5)) * 

+

bpWet + (granSrc * (1 - bpWet)));

+


+

OffsetOut.ar(out, Pan2.ar(src, panMax, amp) * window); 

+

}).add; 

+


+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

w = Buffer.sendCollection(s, Signal.hanningWindow(1024));

+

)

+


+


+

// random types

+


+

// 0: low value

+

// 1: low or high value, evenly distributed

+

// 2: evenly distributed

+

// 3: linear decrease from mean value

+

// 4: exponential distribution

+

// 5: beta distribution, default parameter 0.3 centers value at the borders

+

// 6: brownian movement (of first order) 

+

// 7: brownian movement of second order (stepsize itself generated by brownian movement) 

+


+

// A second order brownian movement much more tends to get stuck at the

+

// borders than a normal (first order) brownian movement

+

// E.g. see Sergio Luque's presentation of Xenakis's stochastic synthesis:

+

// "Stochastic Synthesis, Origins and Extensions", pp 25-28 

+

// http://sergioluque.com

+


+


+

// Function that generates an array of PLx patterns

+

// of different random types (see PLx suite).

+

// These placeholders can refer to environmental variables

+

// to be set by the VarGui interface later on.

+


+

(

+

d = { |keyLo, keyHi, betaProb = 0.3, brownStepFac = 0.01,

+

brown2Ratio = 1, brown2StepFac = 0.01|

+

// keyLo and keyHi must be Symbols,

+

// other args may be Symbols

+

var patLo, patHi, patDif;

+

+

// avoid lo-hi reversing with Pbrown

+

patLo = min(PL(keyLo), PL(keyHi));

+

patHi = max(PL(keyLo), PL(keyHi));

+

patDif = patHi - patLo;

+

[ 

+

PL(keyLo),

+

Pfunc { currentEnvironment[[keyLo, keyHi].choose] },

+

PLwhite(keyLo, keyHi),

+

PLmeanrand(keyLo, keyHi),

+

PLexprand(keyLo, keyHi), 

+

PLbeta(keyLo, keyHi, betaProb, betaProb), 

+

PLbrown(patLo, patHi, patDif * PL(brownStepFac)), 

+

PLbrown(patLo, patHi, 

+

PLbrown(

+

    patDif.neg * PL(brown2Ratio) / 2, 

+

    patDif * PL(brown2Ratio) / 2,

+

    patDif * PL(brown2Ratio) * PL(brown2StepFac)

+

    )

+

) 

+

]

+

};

+

)

+


+

// trigrate, granDur, rate and bpFreq are 

+

// chosen between bounds according to the 

+

// random distribution type notated with suffix D

+


+

// single grains are filtered with a bandpass

+

// amount of effect controlled with bpWet

+


+

(

+

p = Pbind( 

+

\instrument, \gran_2b, 

+

\sndBuf, b,

+

\windowBuf, w, 

+

+

\dur, 1 / PLswitch1(d.(\trigRateLo, \trigRateHi), \trigRateD), 

+

\granDur, PLswitch1(d.(\granDurLo, \granDurHi), \granDurD), 

+

\time, Ptime(),

+

\posRate, PL(\posRate),  

+

\pos, Pfunc { |e|

+

var relTime = ~posRate * e.time / e.sndBuf.duration, relDif;

+

relDif = ~posHi - ~posLo;

+

relTime + rand2(~posDev) % relDif + ~posLo;

+

},

+

\rate, PLswitch1(d.(\rateLo, \rateHi), \rateD),

+

\bpFreq, PLswitch1(d.(\bpFreqLo, \bpFreqHi), \bpFreqD),

+

\bpRQ, PL(\bpRQ),

+

\bpWet, PL(\bpWet),

+

 

+

\amp, PL(\amp),

+

\panMax, PLseq([-1,1]) * PL(\panMax),

+

\out, 0

+

);

+


+

VarGui([

+

\posLo, [0.0, 0.99, \lin, 0.01, 0.21],

+

\posHi, [0.0, 0.99, \lin, 0.01, 0.47],

+

\posRate, [0.1, 2, \lin, 0.01, 0.2],

+

\posDev, [0, 0.2, 5, 0, 0.002],

+


+

\trigRateLo, [1, 200, \lin, 0.01, 21],

+

\trigRateHi, [1, 200, \lin, 0.01, 155],

+

\trigRateD, [0, 7, \lin, 1, 6],

+

+

\granDurLo, [0.01, 0.6, \exp, 0.0, 0.037], 

+

\granDurHi, [0.01, 0.6, \exp, 0.0, 0.4], 

+

\granDurD, [0, 7, \lin, 1, 6],

+

+

\rateLo, [0.1, 3, \lin, 0.01, 1.09],

+

\rateHi, [0.1, 3, \lin, 0.01, 1.63],

+

\rateD, [0, 7, \lin, 1, 1],

+

+

\bpFreqLo, [50, 10000, \exp, 0.1, 54],

+

\bpFreqHi, [50, 10000, \exp, 0.1,8275],

+

\bpFreqD, [0, 7, \lin, 1, 1],

+

\bpRQ, [0.01, 0.99, \lin, 0.0, 0.07], 

+

\bpWet, [0.0, 1, \linear, 0.0, 0.23],

+

+

\panMax, [0.0, 1, \lin, 0.0, 0.85],

+

\amp, [0.0, 1, \lin, 0.01, 0.25]

+

], stream: p

+

).gui(varColorGroups: (0..19).clumps([4,3,3,3,5,1,1]))

+

)

+


+


+

Example 2c:   Generating granular phrases with Pspawner

+


+


+

// This example needs SynthDef \gran_2b and Function d to be taken from Ex. 2b

+


+


+

(

+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

w = Buffer.sendCollection(s, Signal.hanningWindow(1024));

+

)

+


+

// A simple form of Pspawner is used to generate phrases.

+

// Phrase length params are taken a bit roughly as sustain and 

+

// rest times also depend on randomly varying grain lengths.

+

// spSustain controls medium sustain time (without grain length overhead)

+

// spLegato controls medium legato factor (disregarding reduction by grain length overhead)

+

// spDev is causing separate random deviation of spSustain and spLegato 

+

// between 1/(1+spDev) and 1+spDev

+


+

// random distribution switching is restricted here to

+

// types 6 and 7 (random walks of first and second order)

+

// to force individual sound qualities of phrases.

+


+

(

+

// declare var here as pattern is repeatedly evaluated from within the Pspawner,

+

// interpreter variable would be unsafe if running examples in parallel

+


+

var p = Pbind( 

+

\instrument, \gran_2b, 

+

\sndBuf, b,

+

\windowBuf, w, 

+

+

\dur, 1 / PLswitch1(d.(\trigRateLo, \trigRateHi), \trigRateD), 

+

\granDur, PLswitch1(d.(\granDurLo, \granDurHi), \granDurD), 

+

\time, Ptime(),

+

\posRate, PL(\posRate),  

+

+

// random timeOffset added with each spawning

+

\pos, Pfunc { |e|

+

var relTime = ~posRate * e.time / e.sndBuf.duration + e.timeOffset, relDif;

+

relDif = ~posHi - ~posLo;

+

relTime + rand2(~posDev) % relDif + ~posLo;

+

},

+

\rate, PLswitch1(d.(\rateLo, \rateHi), \rateD),

+

\bpFreq, PLswitch1(d.(\bpFreqLo, \bpFreqHi), \bpFreqD),

+

\bpRQ, PL(\bpRQ),

+

\bpWet, PL(\bpWet),

+

 

+

\amp, PL(\amp),

+

\panMax, PLseq([-1,1]) * PL(\panMax),

+

\out, 0

+

);

+


+

q = Pspawner({ |sp|

+

var randomizer = { |x| var y = rand(x); 0.5.coin.if { 1 + y }{ 1 / (1 + y) } },

+

sus, legato, delta; 

+

+

loop {

+

sus = ~spSustain * randomizer.(~spDev);

+

legato = ~spLegato * randomizer.(~spDev);

+

+

// take random offset for each phrase

+

sp.par(Pfindur(sus, Psetpre(\timeOffset, 5.0.rand, p)));

+

delta = sus / (~spLegato * randomizer.(~spDev));

+

sp.wait(delta)

+

}

+

});

+


+

VarGui([

+

\posLo, [0.0, 0.99, \lin, 0.01, 0.16],

+

\posHi, [0.0, 0.99, \lin, 0.01, 0.41],

+

\posRate, [0.1, 2, \lin, 0.01, 1.4],

+

\posDev, [0, 0.2, 5, 0, 0.0017],

+


+

\trigRateLo, [1, 200, \lin, 0.01, 70],

+

\trigRateHi, [1, 200, \lin, 0.01, 150],

+

\trigRateD, [6, 7, \lin, 1, 7],

+

+

\granDurLo, [0.01, 0.6, \exp, 0.0, 0.02], 

+

\granDurHi, [0.01, 0.6, \exp, 0.0, 0.11], 

+

\granDurD, [6, 7, \lin, 1, 6],

+

+

\rateLo, [0.1, 3, \lin, 0.01, 0.2],

+

\rateHi, [0.1, 3, \lin, 0.01, 1.86],

+

\rateD, [6, 7, \lin, 1, 7],

+

+

\bpFreqLo, [50, 10000, \exp, 0.1, 67],

+

\bpFreqHi, [50, 10000, \exp, 0.1, 5885],

+

\bpFreqD, [6, 7, \lin, 1, 6],

+

\bpRQ, [0.01, 0.99, \lin, 0.0, 0.17], 

+

\bpWet, [0.0, 1, \linear, 0.0, 0.38],

+

+

\spSustain, [0.2, 2, \linear, 0.0, 0.884],

+

\spLegato, [0.6, 1.2, \linear, 0.0, 0.996],

+

\spDev, [0.0, 1, \linear, 0.0, 0.41],

+


+

\panMax, [0.0, 1, \lin, 0.0, 0.85],

+

\amp, [0.0, 1, \lin, 0.01, 0.35]

+

], stream: q

+

).gui(varColorGroups: (0..22).clumps([4,3,3,3,5,3,1,1]) )

+

)

+


+


+


+

Example 2d:   Wave sets

+


+


+

// For this example you need Alberto de Campo's Wavesets class 

+

// (Quark extension, implementation following definitions of Trevor Wishart)

+

// and the Function d from Ex. 2b

+


+

// the wave set player synth optionally adds a BPF applied to the signal, 

+

// amount can be controlled with bpWet

+

// attack and release time > 0 for smoothening

+


+

(

+

SynthDef(\wsPlayer, { arg out = 0, buf = 0, start = 0, length = 441, 

+

rate = 1, att = 0.03, rel = 0.03, wvDur = 1, panMax = 0, amp = 0.2, 

+

delayL = 0.0, delayR = 0.0, bpFreq = 500, bpRQ = 0.5, bpWet = 1; 

+

var phasor, env, granSrc, src, attEff, relEff, sus;

+

+

phasor = Phasor.ar(0, BufRateScale.ir(buf) * rate, 0, length) + start;

+

attEff = min(att, wvDur/2);

+

relEff = min(rel, wvDur/2);

+

sus = wvDur - attEff - relEff;

+


+

env = EnvGen.ar(Env([0, 1, 1, 0], [attEff, sus, relEff], \sine), doneAction: 2);

+

granSrc = BufRd.ar(1, buf, phasor);

+

src = (BPF.ar(granSrc, bpFreq, bpRQ, mul: (bpRQ ** -1) * (400 / bpFreq ** 0.5)) * 

+

bpWet + (granSrc * (1 - bpWet)));

+

OffsetOut.ar(out, Pan2.ar(src, panMax, amp) * env);

+

}).add;

+


+


+

a = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

b = Buffer.read(s, a);

+

w = Wavesets.from(a);

+


+

// relative positions of zero crossings

+

x = w.fracXings.drop(-1) / w.numFrames;

+

)

+


+


+

// Note that trigRate / event duration is not controlled directly in this setup,

+

// it's derived from wave set length (may vary) and legato factor. 

+

// For short wave sets and a low legato value durs could become so short that 

+

// a sudden mass of grains could cause hangs.

+

// To avoid this a parameter maxTrigRate is invented.

+


+

// As wavesets start at distinguished positions in the buffer and 

+

// - together with legato - durations are determined,

+

// an additionally given position rate in general cannot result in a "correct"

+

// looping through the buffer, there will be a deviation.

+

// Here two types of approximation can be choosen with posType:

+

// Type 0 takes the waveset nearest to the calculated exact position.

+

// Type 1 linearly maps positions to wave set indices.

+

// As wave sets are of different length the latter is a rough heuristic

+

// accelerating buffer parts with relatively low frequencies. 

+


+

(

+

p = Pbind(

+

\instrument, \wsPlayer,

+

+

// refering to interpreter variables within Pfuncs 

+

// when running several examples in parallel is unsafe,

+

// so pass them here, then access from within the event

+

+

\b, b,

+

\w, w,

+

\x, x,

+

+

\time, Ptime(),

+

\posLo, PL(\posLo),

+

\posHi, PL(\posHi),

+

\posRate, PL(\posRate),

+

+

\pos, Pfunc { |e| (e.time * e.posRate / e.b.duration) % 

+

(e.posHi - e.posLo) + e.posLo },

+


+

// Estimation of ws index from relative position, see explanation above,

+

// indexIn might be a bottleneck with large buffers,

+

// also a more rough estimation of ws index could be used:

+

// \startWs, Pfunc { |e| e.pos.linlin(0, 1, 0, e.w.xings.size - 2).round.asInteger }

+

+

\startWs, Pfunc { |e| 

+

(~posType == 0).if {

+

e.x.indexIn(e.pos)

+

}{

+

e.pos.linlin(e.posLo, e.posHi, e.x.indexIn(e.posLo), e.x.indexIn(e.posHi))

+

.round.asInteger 

+

}

+

},

+


+

\numWs, PLswitch1(d.(\numWsLo, \numWsHi), \numWsD),

+

\repeats, PLswitch1(d.(\repeatsLo, \repeatsHi), \repeatsD),

+

+

\bpFreq, PLswitch1(d.(\bpFreqLo, \bpFreqHi), \bpFreqD),

+

\bpRQ, PL(\bpRQ),

+

\bpWet, PL(\bpWet),

+

+

\rate, PLswitch1(d.(\rateLo, \rateHi), \rateD),

+

\data, Pfunc { |e| e.w.frameFor(e.startWs, e.numWs)  },

+

+

\buf, b.bufnum,

+

\start, Pkey(\data).collect(_[0]), // startFrame

+

\length, Pkey(\data).collect(_[1]), // length (frameNum)

+

\wvDur, Pkey(\data).collect(_[2]) * Pkey(\repeats), // sustain time

+

+

\calculatedDur, Pkey(\wvDur) / PLswitch1(d.(\legatoLo, \legatoHi), \legatoD),

+

\dur, Pfunc { |e| max(e.calculatedDur, 1 / ~maxTrigRate) },

+


+

\panMax, PLseq([-1,1]) * PL(\panMax),

+

\amp, PL(\amp),

+

\out, 0

+

);

+


+


+

VarGui([

+

\posLo, [0, 1, \lin, 0.0, 0.15],

+

\posHi, [0, 1, \lin, 0.0, 0.45],

+

\posRate, [0.0, 2, \lin, 0.01, 0.25],

+

\posType, [0, 1, \lin, 1, 0],

+

+

\numWsLo, [1, 100, \lin, 1, 5],

+

\numWsHi, [1, 100, \lin, 1, 23],

+

\numWsD, [0, 7, \lin, 1, 6],

+

+

\repeatsLo, [1, 4, \lin, 1, 1],

+

\repeatsHi, [1, 4, \lin, 1, 2],

+

\repeatsD, [0, 7, \lin, 1, 6],

+

+

\maxTrigRate, [1, 250, \lin, 1, 200],

+

+

\bpFreqLo, [50, 10000, \exp, 0.1, 67],

+

\bpFreqHi, [50, 10000, \exp, 0.1, 9600],

+

\bpFreqD, [0, 7, \lin, 1, 7],

+

\bpRQ, [0.01, 0.99, \lin, 0.005, 0.22],

+

\bpWet, [0.0, 1, \lin, 0.005, 0.0],

+

+

\rateLo, [0.05, 2, \lin, 0.0, 0.32],

+

\rateHi, [0.05, 2, \lin, 0.0, 1.3],

+

\rateD, [0, 7, \lin, 1, 7],

+

+

\att, [0.0, 0.05, \lin, 0.001, 0.001],  

+

\rel, [0.0, 0.05, \lin, 0.001, 0.001], 

+

+

\panMax, [0.0, 1, \lin, 0, 0.8],

+

\legatoLo, [0.3, 25, \exp, 0, 0.4],

+

\legatoHi, [0.3, 25, \exp, 0, 5.5],

+

\legatoD, [0, 7, \lin, 1, 7],

+

\amp, [0.0, 2.0, \lin, 0.0, 0.7]  

+

], 

+

stream: p

+

).gui(varColorGroups: (0..25).clumps([4,3,3,1,5,3,2,1,3,1]))

+

)

+


+


+


+

3.) Hybrid Implementations

+


+

Example 3a:   Granulation with ugen plus step sequencing

+


+


+

// Here the trigger for the TGrains ugen comes from a Pbind

+

// which also generates rates like a step sequencer

+


+


+

(

+

SynthDef(\gran_3a, { arg out = 0, posLo = 0.0, posHi = 1.0, 

+

posRate = 1, posDev = 0.01, bufNum = 0, t_trig = 0, 

+

granDur = 0.1, t_rate = 1.0, rateDev = 0, 

+

panMax = 1, amp = 0.1, interp = 4;

+

+

var pan, pos, bufDur, bufDurSection, posDif;

+

+

posDif = posHi - posLo;

+

bufDur = BufDur.kr(bufNum);

+

bufDurSection = bufDur * posDif;

+

pos = posLo * bufDur +

+

(Phasor.ar(0, BufRateScale.kr(bufNum) * posRate / SampleRate.ir, posLo * bufDur, posHi * bufDur) + 

+

(TRand.kr(-0.5, 0.5, t_trig) * posDev * bufDur)).mod(bufDurSection);  

+

pan = Demand.kr(t_trig, 0, Dseq([panMax, panMax.neg], inf) * 0.999);

+

Out.ar(out, TGrains.ar(2, t_trig, bufNum, t_rate, pos, granDur, pan, 1, interp) * amp);

+

}, metadata: (

+

specs: (

+

posLo: [0.01, 0.99, \lin, 0.01, 0.2],

+

posHi: [0.01, 0.99, \lin, 0.01, 0.75],

+

posRate: [0.1, 2, \lin, 0.01, 1],

+

posDev: [0, 0.2, 5, 0, 0.01],

+

panMax: [0.0, 1, \lin, 0.005, 0.8],

+

amp: [0.0, 1, \lin, 0.005, 0.5]

+

)

+

)

+

).add;

+


+


+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+

)

+


+


+

// As the setting Pbind needs to know the Synth's nodeID

+

// the Synth has to be started explicitely and passed to the VarGui later on

+

// (VarGui takes Synths as well as SynthDefs, passing a SynthDef is recommended in general).

+

// The Synth starts silently as t_trig defaults to 0.

+


+


+

(

+

x = Synth(\gran_3a, [\bufNum, b]).register;

+


+

p = Pbind(

+

\type, \set,

+

\id, x,

+

\args, [\t_trig, \t_rate, \granDur],

+

+

\dur, PL(\dur),

+

\granDur, Pkey(\dur) * PL(\legato),

+

\t_trig, 1,

+

\t_rate, PLseq(\midi).midiratio

+

);

+

)

+


+


+

// Do start and pause with the Pbind (EventStreamPlayer) player.

+

// If you stop the Synth you cannot resume audio with a new Synth

+

// as the EventStreamPlayer has lost the correct nodeID

+

// (however the Synth can be paused and resumed).

+


+


+

(

+

VarGui(varCtr: [

+

\dur, [0.01, 0.1, \lin, 0, 0.05], 

+

\legato, [0.3, 3, \lin, 0, 2], 

+

\midi, [-12, 12, \lin, 1, 1] ! 8 

+

], synth: x, stream: p

+

).gui;

+

)

+


+


+

Example 3b:   Using external control synths

+


+


+

// Example needs SynthDef from Ex. 2a

+


+

// Also with language-driven granulation 

+

// controls can be delegated to separate Synths,

+

// which output to control busses.

+

// Control inputs of single synths can read from

+

// these busses (comfortably use aBus.asMap in the Pbind)

+

// or synths can read from busses with In.kr (needs extra definition).

+


+

// A nearby parameter to determine with a separate synth is grain position

+


+

(

+

SynthDef(\bufPhasor, { |out = 0, sndBuf = 0, posRate = 1, posLo = 0, posHi = 1, posDev = 0.01| 

+

var pos, posDif;

+

posDif = posHi - posLo;

+

pos = Phasor.ar(1, posRate * BufRateScale.kr(sndBuf) / BufFrames.kr(sndBuf), 0, posDif) 

+

+ WhiteNoise.kr(posDev / 2) % posDif + posLo;

+

Out.kr(out, A2K.kr(pos)); 

+

} 

+

).add; 

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

w = Buffer.sendCollection(s, Signal.hanningWindow(1024));

+

c = Bus.control(s,1);

+

)

+


+

// in GUI start EventStreamPlayer and bufPhasor Synth

+


+

(

+

p = Pbind( 

+

\instrument, \gran_2a, 

+

\sndBuf, b,

+

\windowBuf, w, 

+

+

\dur, 1 / PL(\trigRate), 

+

\granDur, PL(\granDur), 

+

+

\pos, c.asMap,

+

\rate, PL(\rate),  

+

\amp, PL(\amp),

+

\panMax, PLseq([-1,1]) * PL(\panMax),

+

\out, 0

+

);

+


+

VarGui([

+

\trigRate, [1, 200, \lin, 0.01, 50],

+

\granDur, [0.01, 0.3, \lin, 0.005, 0.12], 

+

\rate, [0.1, 3, \lin, 0.01, 1],

+

\panMax, [0.0, 1, \lin, 0.0, 0.8],

+

\amp, [0.0, 1, \lin, 0.01, 0.3]

+

],[

+

\out, c.index,

+

\sndBuf, b.bufnum,

+

\posLo, [0, 1, \linear, 0.005, 0], 

+

\posHi, [0, 1, \linear, 0.005, 1],

+

\posRate, [0.1, 2, \linear, 0.01, 1],

+

\posDev, [0, 0.2, 5, 0, 0.01]

+

], 

+

p, \bufPhasor

+

).gui(sliderPriority: \synth, playerPriority: \synth);

+

)

+


+


+


+

Example 3c:   Switching between ugens of external control synths

+


+


+

// Example needs SynthDef from Ex. 2a

+


+

// external control synth for position as in 3a, but with 

+

// different types of movement to select

+


+

(

+

SynthDef(\bufPosLFO, { |out = 0, lfoType = 0, freq = 1, posLo = 0, posHi = 1, posDev = 0.01| 

+

var pos, posDif;

+

posDif = posHi - posLo;

+

pos = WhiteNoise.kr(posDev / 2) + Select.kr(lfoType,

+

[LFDNoise0, LFDNoise1, LFDNoise3].collect(_.kr(freq, posDif))) % posDif + posLo;

+

Out.kr(out, pos); 

+

}).add; 

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

w = Buffer.sendCollection(s, Signal.hanningWindow(1024));

+

c = Bus.control(s,1);

+

)

+


+

// added parallel grains

+

// in GUI start bufPhasor Synth before or together with EventStreamPlayer

+


+

// buffer position movement can be forward and backward

+

// lfoType 0: LFDNoise0 (jumps)

+

// lfoType 1: LFDNoise1 (linear interpolation)

+

// lfoType 2: LFDNoise3 (cubic interpolation, smooth, useful in many control contexts)

+

 

+

(

+

p = Pbind( 

+

\instrument, \gran_2a, 

+

\sndBuf, b,

+

\windowBuf, w, 

+

+

\dur, 1 / PL(\trigRate), 

+

\granDur, PL(\granDur), 

+

+

\pos, c.asMap,

+

\rate, PL(\rate) * PL(\midiAdd).midiratio,

+

\amp, PL(\amp),

+

\panMax, PLseq([-1,1]) * PL(\panMax),

+

\out, 0

+

);

+


+

VarGui([

+

\trigRate, [1, 200, \lin, 0.01, 80],

+

\granDur, [0.01, 0.3, \lin, 0.005, 0.195], 

+

\rate, [0.1, 1.5, \lin, 0.01, 0.6],

+

\midiAdd, [-5, 0].collect([-12, 12, \lin, 1, _]),

+

\panMax, [0.0, 1, \lin, 0.0, 0.95],

+

\amp, [0.0, 1, \lin, 0.01, 0.15]

+

],[

+

\out, c.index,

+

\posLo, [0, 1, \linear, 0.005, 0.15], 

+

\posHi, [0, 1, \linear, 0.005, 0.43],

+

\posDev, [0, 0.2, 5, 0, 0.0],

+

\freq, [0.01, 2, \lin, 0, 0.96],

+

\lfoType, [0, 2, \lin, 1, 2]

+

], 

+

p, \bufPosLFO

+

).gui(sliderPriority: \synth, playerPriority: \synth);

+

)

+


+


+


+

Example 3d:   Pattern-driven sequencing of granular events using demand rate ugens

+


+

// This is basically the same as SynthDef \gran_1d with an additional envelope,

+

// grain position phasor is left out, position is determined by a phasor synth via bus and mapping.

+


+

(

+

// length of demand rate sequence, you might want to check larger sizes

+

// in connection with gui arg tryColumnNum > 1

+

~n = 5;

+


+


+

SynthDef(\gran_3d, { |out = 0, soundBuf, envBuf, att = 0.1, sus = 1, rel = 1, pos = 0.5,

+

granDurMul = 1, rateMul = 1, overlapMul = 1, panMul = 1, amp = 0.5, interp = 2| 

+

+

var signal, bufDur, granDur, granGate, relGranDurs, overlap, relOverlaps, overlapSeq, 

+

pan, rate, relRates, rateSeq, granDurSeq; 

+

+

// array args for demand rate sequencing, short form of NamedControl

+

relGranDurs = \relGranDurs.kr(0.1!~n);

+

relRates = \relRates.kr(1!~n); 

+

relOverlaps = \relOverlaps.kr(1!~n); 

+


+

// Dstutter (or Dunique) necessary as granDurSeq is polled twice: granGate and granDur

+

granDurSeq = Dstutter(2, Dseq(relGranDurs, inf));  

+

rateSeq = Dseq(relRates, inf); 

+

overlapSeq = Dseq(relOverlaps, inf); 

+

+

granGate = TDuty.ar(granDurSeq * granDurMul); 

+

granDur = Demand.ar(granGate, 0, granDurSeq * granDurMul);

+

rate = Demand.ar(granGate, 0, rateSeq) * rateMul; 

+

pan = Demand.ar(granGate, 0, Dseq([1, -1], inf)) * 0.999 * panMul; 

+

overlap = Demand.ar(granGate, 0, overlapSeq) * overlapMul;

+


+

bufDur = BufDur.kr(soundBuf);

+

signal = TGrains.ar(2, granGate, soundBuf, rate, pos * bufDur, granDur * overlap, pan, 1, interp) *

+

EnvGen.kr(Env([0, 1, 1, 0], [att, sus, rel]), doneAction: 2);

+

+

Out.ar(out, signal * amp); 

+

}

+

).add; 

+


+

SynthDef(\bufPhasor_2, { |out = 0, sndBuf = 0, posRateE = 0, posRateM = 1, 

+

posLo = 0, posHi = 1, posDev = 0.01| 

+

+

var pos, posDif, posRate;

+

posDif = posHi - posLo;

+

posRate = 10 ** posRateE * posRateM;

+

pos = Phasor.ar(1, posRate * BufRateScale.kr(sndBuf) / BufFrames.kr(sndBuf), 0, posDif) 

+

+ WhiteNoise.kr(posDev / 2) % posDif + posLo;

+

Out.kr(out, A2K.kr(pos)); 

+

} 

+

).add; 

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+

c = Bus.control(s,1);

+

)

+


+


+

// Pattern control of granular events

+


+

// Every granular event gets a duration between durLo and durHi (exp distribution)

+

// and an envelope according to att, sus and rel.

+

// One of four events is randomly defined as rest. 

+


+

// arg arrays relGranDurs, relRates and relOverlaps determine

+

// demand rate sequencing for granulation as in Ex. 1d.

+

// Per event they are multiplied with corresponding factors

+

// limited by granDurMulLo/Hi, rateMulLo/Hi and overlapMulLo/Hi

+


+

// start phasor synth (first row in player console) before event stream player

+

// event stream player might start with rest 

+


+


+

(

+

// Passing arrayed args with an event pattern requires

+

// wrapping them into an array or Ref object.

+

// This is necessary to distinguish from triggering 

+

// several synths per event.

+

// .collect(`_) is short for .collect { |x| Ref(x) }

+

// .collect([_]) or .collect { |x| [x] } would also be possible

+


+

p = Pbind(

+

\instrument, \gran_3d,

+

\soundBuf, b,

+

\pos, c.asMap,

+

+

\dur, PLexprand(\durLo, \durHi),

+

\type, PLshufn(\note!3 ++ \rest),

+

\att, PL(\att),

+

\sus, PL(\sus),

+

\rel, PL(\rel),

+


+

+

\relGranDurs, PL(\relGranDurs).collect(`_),

+

\granDurMul, PLwhite(\granDurMulLo, \granDurMulHi),

+


+

\relOverlaps, PL(\relOverlaps).collect(`_),

+

\overlapMul, PLwhite(\overlapMulLo, \overlapMulHi),

+

+

\relRates, PL(\relRates).collect(`_),

+

\rateMul, PLwhite(\rateMulLo, \rateMulHi),

+

+

\panMul, PL(\panMul),

+

\amp, PL(\amp)

+

);

+


+

VarGui([

+

\durLo, [0.05, 1.5, \lin, 0, 0.16],

+

\durHi, [0.05, 1.5, \lin, 0, 1.2],

+

\att, [0.01, 0.6, \lin, 0, 0.4],

+

\sus, [0.01, 0.6, \lin, 0, 0.05],

+

\rel, [0.01, 0.6, \lin, 0, 0.5],

+

\relGranDurs, { |i| [0.01, 0.1, \lin, 0, i * 0.005 + 0.02] } ! ~n,

+

\granDurMulLo, [0.03, 2, \lin, 0, 0.05],

+

\granDurMulHi, [0.03, 2, \lin, 0, 1.8],

+

+

\relRates, { |i| [0.1, 1.5, \lin, 0, (5-i) * 0.1 + 0.5] } ! ~n,

+

\rateMulLo, [0.1, 2, \lin, 0, 0.5],

+

\rateMulHi, [0.1, 2, \lin, 0, 1.5],

+


+

\relOverlaps, [0.5, 3, \lin, 0, 2] ! ~n,

+

\overlapMulLo, [0.1, 2, \lin, 0, 0.25],

+

\overlapMulHi, [0.1, 2, \lin, 0, 1.8],

+

+

\panMul, [0.0, 1, \lin, 0.0, 0.8],

+

\amp, [0.0, 3, \lin, 0.01, 1.8]

+

],[

+

\out, c.index,

+

\sndBuf, b.bufnum,

+

\posLo, [0, 1, \lin, 0.005, 0.1], 

+

\posHi, [0, 1, \lin, 0.005, 0.9],

+

\posRateE, [-3, 4, \lin, -1, 0],

+

\posRateM, [0.1, 10, \exp, 0.01, 1],

+

\posDev, [0, 0.2, 5, 0, 0.01]

+

], 

+

p, \bufPhasor_2

+

).gui(

+

tryColumnNum: 2,

+

sliderPriority: \synth, 

+

playerPriority: \synth,

+

varColorGroups: (0..(~n*3+12)).clumps([2,3,~n+2,~n+2,~n+2,1,1]), 

+

synthColorGroups: (0..6).clumps([1,1,2,2,1]), 

+

labelWidth: 90,

+

sliderWidth: 300

+

);    

+

)

+


+


+

4.) Extensions of Setups

+


+


+

.) Changing ranges and scaling

+


+

This concerns all control parameters in question. E.g. the layering of long grains (> 200 ms) in connection with small rates of position changes (posRate) often has interesting effects. One may want to drop the term granulation in that case, though it's the same structure of synthesis. For such parameters with a very large coefficient boundHi / boundLo one may take exponential scaling, and if this is not fine enough you can invent a control pair of mantissa and exponent (as for posRate in Ex. 1b).

+

+

.) Parameter linkage

+


+

On the one hand a logical restriction, on the other hand it can make sense from a musical / perceptional point of view. E.g. shortening of grains could be linked with a raise of rate (as low frequencies might fail to unfold in short grains). Anyway parameter linkage is reducing complexity - it's a trade-off between simplicity of the interface and exclusion of certain constellations which should be considered from case to case.

+

+

.) Inventing and extending controls and LFO changes dependant on specific buffers and parameter sets

+


+

Say one has started playing around with a certain buffer and a general granulation patch. A parameter set that gives an interesting sound may react in a very interesting way on a change of a single parameter e.g., trigger rate. Then it may be an option to build in a control or a LFO specifically designed for that parameter - LFO is meant here in a general sense, it could be a LFO in a Synth, a dedicated LFO synth or defined by a rapidly sequencing Pattern.

+


+

.) Iterated granulation

+


+

Granulation of buffers themselves resulting from buffer granulation can give interesting effects.

+


+

.) Spatialization

+


+

For the sake of ease and comparison a L/R-switch per grain with one panning parameter was used in the examples above. Needless to say that spatial scattering of grains remains a large field of experimentation. Generally spoken spatialization can be part of the synthesis process or carried through independently afterwards, but also a combination of both approaches is feasible.

+

+

.) Effects

+


+

Effect processing can be applied to all or single grains in a language-driven granulation setup. There can be one or more effects, serial or in parallel, defined outside or inside the Synth playing the buffer, as with the BPF in Ex 2b - 2d. In these examples the bandpass is applied in general, but also a sequencing of effects can be done. And even in the case of just one effect (e.g. reverb) a decent sequencing of Fx- / noFx-events can sound very interesting. This can be done with PbindFx (as in the project kitchen studies), sequencing not more than one effect per grain can be done straightly: continously running effect synths read from different buses and events with different out values cause the player synths to output to these buses. 

+

 

+

 .) Micro rhythm

+


+

See Xenakis' suggestion of Sieves with rhythm generation as a special application, a granulation example is contained in the example section of: Sieves and Psieve patterns. PSPdiv, a dynamic multi-layer pulse divider, which is based on Pspawner, can also be used in this context, see the last example of PSPdiv. 

+

 

+

 

+

 

+

 

+

 

+ + diff --git a/Help/DIdev.html b/Help/DIdev.html new file mode 100755 index 0000000..00d7b08 --- /dev/null +++ b/Help/DIdev.html @@ -0,0 +1,449 @@ + + + + + + + + + + + +

DIdev pseudo drate ugen, searches for numbers with integer distance from a source signal, optionally avoiding repetitions within a span

+


+

Part of: miSCellaneous

+


+

Inherits from: DUGen

+


+

DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples.

+


+

NOTE: DIdev needs at least a SC version >= 3.7.0 for proper working.

+


+

NOTE: It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples.

+


+

NOTE: In contrast to PIdev and PLIdev, DIdev needs to know maximum deviations (minLoDev, maxHiDev) beforehand. Together with maxLookBack they determine multichannel sizes, so a relatively high number of ugens might be involved. 

+


+

See also: Idev suite, PIdev, PLIdev

+


+


+

Creation / Class Methods

+


+

Creates a new DIdev object.

+

+

*new (in, maxLookBack = 3, minLoDev = -3, maxHiDev = 3, lookBack, loDev, hiDev, thr = 1e-3, length = inf)

+

+

in - The source signal, integer distances are calculated from the value of this signal with each trigger.

+

Can be demand rate or other ugen.

+

maxLookBack - Integer, the maximum lookback span. Cannot be modulated, defaults to 3.

+

minLoDev - Integer, the minimum low deviation (must not be exceeded by any loDev value). 

+

Should be negative, cannot be modulated, defaults to -3.

+

maxHiDev - Integer, the maximum high deviation (must not be exceeded by any hiDev value).  

+

Should be positive, cannot be modulated, defaults to 3.

+

lookBack - Determines the current lookback span for avoiding repetitions.

+

Can be modulated (demand rate or other ugen, no ar) but must not exceed maxLookBack.

+

If no value is passed, then maxLookBack is taken.

+

loDev - Determines the current low deviation for the search.

+

Can be modulated (demand rate or other ugen) but must not exceed minLoDev.

+

If not specified, them minLoDev is taken. 

+

hiDev - Determines the current high deviation for the search.

+

Can be modulated (demand rate or other ugen) but must not exceed maxHiDev.

+

If not specified, then maxHiDev is taken. 

+

thr - Threshold for equality comparison. Can be modulated (demand rate or other ugen).

+

Defaults to 1e-3. 

+

length - Number of repeats. Defaults to inf. 

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

Ex.1) Basic usage: random choice within region without repetitions

+

+

// constant source (72), max deviation +/- 3

+

// no repetition within 5 pitches

+


+

(

+

x = {

+

var trig = Impulse.ar(5);

+

var midi = Demand.ar(trig, 0, DIdev(72, 2, -1, 2));

+

midi.poll(5, label: \midi);

+

SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1

+

}.play;

+

)

+


+

x.release

+


+


+


+

Ex.2) Variable deviations and lookBack

+


+

(

+

x = {

+

|loDev = -6, hiDev = 5, lookBack = 2|

+

var trig = Impulse.ar(5);

+

// define maxLookBack, minLoDev and maxHiDev

+

var midi = Demand.ar(trig, 0, DIdev(72, 11, -6, 5, lookBack, loDev, hiDev));

+

midi.poll(5, label: \midi);

+

SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1

+

}.play;

+

)

+


+


+

// as lookBack equals 2, this defines a fixed sequence (up or down anyway)

+


+

(

+

x.set(\loDev, -1);

+

x.set(\hiDev, 1)

+

)

+


+


+

// widen range

+


+

(

+

x.set(\loDev, -6);

+

x.set(\hiDev, 5);

+

)

+


+


+

// force a twelve-tone row

+


+

x.set(\lookBack, 11)

+


+


+

// contradictory input, lookBack 11 not possible within range, causes repetitions

+


+

(

+

x.set(\loDev, -3);

+

x.set(\hiDev, 2)

+

)

+


+

x.release

+


+


+

Ex.3) Moving source signal

+


+

(

+

x = {

+

|loDev = -1, hiDev = 1, lookBack = 2|

+

var trig = Impulse.ar(7);

+

// define maxLookBack, minLoDev and maxHiDev

+

// source is rounded to integers here

+

var midi = Demand.ar(trig, 0, DIdev(SinOsc.ar(0.2, 0, 15, 82).round, 11, -6, 5, lookBack, loDev, hiDev));

+

midi.poll(7, label: \midi);

+

SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1

+

}.play;

+

)

+


+


+

// widen range and increase lookBack

+


+

(

+

x.set(\loDev, -6);

+

x.set(\hiDev, 5);

+

x.set(\lookBack, 10);

+

)

+


+

x.release

+


+


+


+

Ex.4) Dynamic deviation range and lookBack

+


+

// lookBack and deviations coupled here

+

// maxLookBack, minLoDev and maxHiDev must be large enough

+


+

(

+

x = {

+

var trig = Impulse.ar(7);

+

var dev = SinOsc.ar(0.1, -pi/2).range(1, 5);

+

var midi = Demand.ar(trig, 0, 

+

DIdev(78, 10, -5, 5, 

+

SinOsc.kr(0.1, -pi/2).range(1, 5).round.poll(label: \lookBack),

+

dev.neg.poll(label: \loDev),

+

dev.poll(label: \hiDev)

+

)

+

);

+

    SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) ! 2

+

}.play;

+

)

+


+

x.release

+


+


+

// loDev and hiDev can be demand rate

+


+

(

+

x = {

+

    var trig = Impulse.ar(5);

+

var hiDev = Dseq([1, 10], inf);

+

    var midi = Demand.ar(trig, 0,

+

        DIdev(78, 10, -10, 10,

+

1,

+

            Dseq([-10, 5], inf),

+

            Dseq([-5, 10], inf)

+

        )

+

    );

+

    SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) ! 2

+

}.play;

+

)

+


+

x.release

+


+


+

// lookBack can also be demand rate

+


+

(

+

x = {

+

    var trig = Impulse.ar(5);

+

var hiDev = Dseq([1, 10], inf);

+

    var midi = Demand.ar(trig, 0,

+

DIdev(70, 10, -15, 15,

+

Dstutter(4, Dseq([1, 3], inf)),

+

Dstutter(4, Dseq([-9, 7], inf)),

+

Dstutter(4, Dseq([-8, 10], inf))

+

        )

+

    );

+

midi.poll(trig);

+

SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) ! 2 * EnvGen.ar(Env.asr(0.15))

+

}.play;

+

)

+


+

x.release

+


+


+


+

Ex.5) Non-integer source

+


+

(

+

x = {

+

|lookBack = 3, thr = 1|

+

var trig = Impulse.ar(7);

+

// for a non-integer source it makes sense to take a sufficiently large threshold thr

+

var midi = Demand.ar(trig, 0, DIdev(SinOsc.ar(0.2, 0, 15, 82), 5, -6, 5, lookBack, thr: thr));

+

midi.poll(7, label: \midi);

+

SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1

+

}.play;

+

)

+


+

// close floats can occur here 

+

x.set(\thr, 0.01)

+


+

// not here

+

x.set(\thr, 2)

+


+

x.release

+


+


+


+
Ex.6) Multichannel expansion

+

 

+


+

// nothing especially implemented

+


+

(

+

x = {

+

var trig = Impulse.ar(7);

+

var in = [0, 8.5];

+

var maxLookBack = [1, 3];

+

var loDev = [-1, -5];

+

var hiDev = [1, 5];

+

var midi = { |i| Demand.ar(trig, 0,

+

DIdev(

+

in[i] + SinOsc.ar(0.1, -pi/2).range(65, 85).round,

+

maxLookBack: maxLookBack[i],

+

loDev: loDev[i],

+

hiDev: hiDev[i]

+

).dpoll(label: "midi_" ++ (i == 0).if { "lo" }{ "hi"})

+

) } ! 2;

+

SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1)

+

}.play;

+

)

+


+

x.release

+


+


+

Ex.7) Application to other params: rhythm

+

 

+

// if we have indexed data for whatever, we can slide over it

+

// prepare some rhythms in order

+

// use them for SynthDef

+


+

(

+

~rhythmBase = [

+

[1, 1],

+

[2, 1, 1],

+

[1, 1, 2],

+

].collect(_.normalizeSum);

+


+

~rhythms = ~rhythmBase *.x [1, 2];

+

~rhythmNum = ~rhythms.size;

+

~rhythms = ~rhythms.scramble;

+


+

"rhythm types: ".postln;

+

~rhythms.do { |r, i| i.post; ": ".post; r.postln };

+


+

SynthDef(\sine_rhythm, { |out = 0, freq = 400, att = 0.01, rel = 0.1, gate = 1, amp = 0.2|

+

var trig, loDev = -1, hiDev = 1, sig, src,

+

rhy = ~rhythmNum.collect { |i| Dseq(~rhythms[i], 1) };

+


+

trig = TDuty.ar(

+

Dswitch(rhy,

+

// be careful not to exceed range of rhythm indices, which can result in server quit

+

Dpoll(

+

DIdev(SinOsc.ar(0.1).range(loDev.abs, ~rhythmNum - hiDev - 1).round, 2, loDev, hiDev),

+

'rhythm type'

+

)

+

) * 0.3

+

);

+

src = SinOsc.ar(Demand.ar(trig, 0, LFDNoise3.ar([0.5, 3], [10, 15], [60, 85])).midicps);

+

sig = Decay2.ar(trig, att, rel) * src;

+

Out.ar(out, sig * EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2) * amp);

+

}).add;

+

)

+


+

x = Synth(\sine_rhythm)

+


+

x.release

+


+


+

Ex.8) Proof of concept

+


+

(

+

// Function to check an array for repetitions within a maximum test span

+


+

~repetitionCheck = { |array, maxTestSpan|

+

maxTestSpan.do { |i|

+

var result = (array.drop(i+1) - array).drop((i+1).neg).includes(0).not;

+

("no repetitions within a span of " ++ (i+2).asString ++ " items: ").post;

+

result.postln;

+

}

+

};

+


+

// prepare buffer to store DIdev values 

+


+

n = 10000; // buffer size

+

r = 10000; // trigger rate

+

b = Buffer.alloc(s, n);

+

)

+


+


+

// run to store, wait until finished (a bit more than 1 second)

+

(

+

{

+

var trig = Impulse.ar(r);

+

Demand.ar(trig, 0, Dbufwr(DIdev(Dbrown(0, 20, 0.3).round, 5, -7, 7), b, Dseries(0, 1, n), 0));

+

Line.ar(dur: n / r + 0.1, doneAction: 2);

+

0

+

}.play;

+

)

+


+

// move data to language

+


+

b.loadToFloatArray(action: { |x| a = x.asInteger; "array filled \n".postln; })

+


+


+

// no repetitions within a maximum span of 6 (maxLookBack was 5)

+


+

~repetitionCheck.(a, 10);

+


+


+


+

Ex.9) Switching signals with DXMix

+


+

// source of 10 stereo granulations:

+

// they differ in position movement, trigrate and rate

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+

(

+

x = {

+

var pos = { |i| SinOsc.ar(0.02, pi/5 * i).range(0.1, 0.8) } ! 10;

+

var sig;

+


+

sig = pos.collect { |p, i|

+

TGrains.ar(

+

2,

+

trigger: Impulse.ar(i * 10 + 30),

+

bufnum: b,

+

rate: LFDNoise3.ar(0.1).range(0.3, 1.5),

+

centerPos: p * BufDur.ir(b),

+

dur: 0.1,

+

pan: Dseq([-1, 1], inf)

+

)

+

};

+

// switch between stereo sources with DXMix

+

DXMix.ar(

+

Dpoll(DIdev(SinOsc.ar(0.1).range(2, 7).round, 2, -2, 1)),

+

`sig,

+

fadeMode: 1,

+

stepTime: 0.03,

+

fadeTime: 0.002

+

) * 5

+

}.play

+

)

+


+

x.release

+


+


+

// sine stereo sources

+


+

(

+

x = {

+

var sig = (1..20).scramble.collect { |i| 

+

SinOsc.ar(

+

[i, 20-i] * 100 * LFDNoise3.ar(0.1).range(0.97, 1.03), 

+

0, 

+

0.05 * LFDNoise3.ar(1 ! 2).range(0.1, 1)

+

)

+

};

+

DXMix.ar(

+

Dpoll(DIdev(SinOsc.ar(0.05).range(2, 17).round, 2, -2, 2)),

+

`sig,

+

fadeMode: 1,

+

stepTime: 0.03,

+

fadeTime: 0.002

+

) ;

+

}.play

+

)

+


+

x.release

+


+


+ + diff --git a/Help/DX suite.html b/Help/DX suite.html new file mode 100755 index 0000000..9b3a302 --- /dev/null +++ b/Help/DX suite.html @@ -0,0 +1,169 @@ + + + + + + + + + + + +

DX suite pseudo ugens for crossfaded mixing and fanning according to demand-rate control  

+


+

Part of: miSCellaneous

+


+

See also: DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+

DX (Demand XFade) ugens are built upon DemandEnvGen and PanAz and can hence use their dynamic control options. Their user interface and underlying ugen structure is almost identical, due to multichannel expansion they are capable of triggering complex signal flows. As demand rate sequencing can be performed fast, DX ugens can, beneath their functionality as signal distribution controllers in the medium or large time-scale, be used as genuin synthesis tools in the area of microsound, e.g. for fast switching between sources as well as different processings of them. DXEnvFan and DXEnvFanOut give specific options as they can be used as multichannel envelopes and triggers at the same time. This e.g. enables server-side granulation techniques for arbitrary sound sources that are difficult to handle with granulation ugens alone, such es effect sequencing per grain and others. A related application, not necessarily in a granular time-scale, is crossfaded playback from different buffer positions. Finally DX fanning ugens allow server-side definition of spatial movements by crossfading between non-adjacent channels respectively buses.

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

Ex.1) DXMix, crossfade sequencing

+


+

// Crossfaded switching between sources, there exists a number of options, 

+

// e.g. for fade mode (inclusion of steps = plateau phases), curve type and width.

+

// The syntax of passing the sources within a Ref object is necessary

+

// to distinguish from multichannel expansion.

+


+


+

(

+

{

+

DXMix.ar(

+

Dseq([1, 0, 1, 2], inf),

+

`([SinOsc.ar(100), WhiteNoise.ar(), LFTri.ar(100)]),

+

stepTime: 0.015,

+

fadeTime: 0.015,

+

fadeMode: 1, // alternate steps and fades

+

sine: 0, // sine type or not

+

equalPower: 0 // square-rooted (equal power) or not

+

)

+

}.plot(0.12)

+

)

+


+


+


+

Ex.2) Comparison of fanning DX ugens

+

+

// Crossfading source signals with DXFan,

+

// result is a multichannel signal of size that has to be passed

+


+

(

+

{

+

DXFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

SinOsc.ar(500),

+

size: 8,

+

fadeTime: 0.01

+

)

+

}.plot(0.1)

+

)

+


+

(

+

{

+

DXFan.ar(

+

Dseq([2, 0, 4, 6], inf),

+

`(SinOsc.ar([300, 700])),

+

size: 8,

+

fadeTime: 0.01

+

)

+

}.plot(0.1)

+

)

+


+


+

// DXEnvFan returns a multichannel envelope,

+

// the size has to be passed.

+

// Without any options it defaults to the square-rooted (equal power) sine type.

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

)

+

}.plot(0.1)

+

)

+


+

// proof of concept with other fanning DX ugens:

+


+

// for getting the same result with DXFan pass a DC as source

+

(

+

{

+

DXFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

DC.ar(1),

+

size: 8,

+

fadeTime: 0.01

+

)

+

}.plot(0.1)

+

)

+


+

// envelopes can also be sent to buses, for plotting we can get them back with In,

+

// here the size is considered via the bus.

+


+

(

+

a = Bus.audio(s, 8);

+

{

+

DXEnvFanOut.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf) + a.index,

+

fadeTime: 0.01

+

);

+

In.ar(a, 8)

+

}.plot(0.1)

+

)

+


+

// analogously with DXFanOut and DC input

+


+

(

+

b = Bus.audio(s, 8);

+

{

+

DXFanOut.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf) + b.index,

+

DC.ar(1),

+

fadeTime: 0.01

+

);

+

In.ar(b, 8)

+

}.plot(0.1)

+

)

+


+

(

+

a.free;

+

b.free;

+

)

+


+


+


+


+ + diff --git a/Help/DXEnvFan.html b/Help/DXEnvFan.html new file mode 100755 index 0000000..a79d5c7 --- /dev/null +++ b/Help/DXEnvFan.html @@ -0,0 +1,789 @@ + + + + + + + + + + + +

DXEnvFan returns crossfade envelopes according to demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: AbstractDX

+


+

DXEnvFan returns the multichannel envelope signal, which is used by DXMix / DXMixIn / DXFan / DXFanOut implicitely. It can be used as envelope and trigger at the same time, which leads to applications such as crossfading PlayBufs and different kinds of granulation, using a buffer or not. 

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

See also: DX suite, DXMix, DXMixIn, DXEnvFanOut, DXFan, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

Creation / Class Methods

+


+

*ar (out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0)

+

+

out - Determines the sequence of channels between which the signal should be crossfaded.

+

An channel index, a demand rate or other ugen returning channel indices or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of out

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

fadeTime - A fade time, a demand rate or other ugens returning fade times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of fadeTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of fadeTime depends on fadeMode.

+

fadeTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

stepTime - A step time, a demand rate or other ugens returning step times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of stepTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of stepTime depends on fadeMode.

+

stepTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

fadeMode - Integers between 0 and 4 or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

fadeMode = 0: only fadeTimes are used, no steps

+

fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

Defaults to 0.

+

sine - Determines the crossfade type: sine-based or not.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning sine numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of sine

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

equalPower - Determines if crossfading of equal power type (square root) should be applied.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning equalPower numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of equalPower

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

power - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude. If power and curve are passed, power applies before.

+

A positive Number or a demand rate or other ugen returning positive power numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

curve - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude according to the lincurve mapping. 

+

If power and curve are passed, power applies before.

+

A Number or a demand rate or other ugen returning curve numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of curve

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Calculation of curvature is not giving reliable results when width and / or dynOutOffset are 

+

being modulated at the same time.

+

Defaults to 0. 

+

allowTypeSeq - Enables sequencing of sine, equalPower, power and curve with 

+

demand rate ugens and modulating of sine and equalPower with other ugens.

+

A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion.

+

Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0.

+

fadeRate - One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

Defaults to \ar.

+

maxFadeNum - Integer determining the maximum number of fades, after which doneAction applies. 

+

A SequenceableCollection causes multichannel expansion. Not modulatable.

+

Defaults to inf.

+

maxWidth - An Integer determining the maximum width or

+

a SequenceableCollection of such, causing multichannel expansion, width goes into PanAz's width arg.

+

maxWidth increases the internally used and potentially needed number of parallel channels. Not modulatable.

+

Determines the size of the returned multichannel signal.

+

Defaults to 2.

+

width - Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, 

+

causing multichannel expansion. Not modulatable in versions earlier than SC 3.9.

+

It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed maxWidth.

+

In case of  DXEnvFan's use as trigger you might want to set it really smaller than maxWidth.

+

Defaults to 2.

+

initOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines an initial offset for PanAz's pos arg.

+

This can be useful for a start with full or reduced width, see examples. 

+

Not modulatable. Defaults to 0.

+

maxDynOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the maximum dynOutOffset to be expected.

+

maxDynOutOffset increases the internally used and potentially needed number of parallel channels. 

+

Not modulatable. Defaults to 1.

+

dynOutOffset - UGen, Integer or Float or

+

a SequenceableCollection of such, causing multichannel expansion.

+

By passing a ugen the movement between channels can be modulated.

+

Note that a ugen's output must not exceed maxDynOutOffset.

+

Defaults to 0.

+

allowFadeEnd - Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion.

+

Determines if a demand rate input to out with finite length will be monitored, which needs a quite complicated 

+

trigger logic and more running ugens. If set to 0, the behaviour after the end of out is undefined.

+

Defaults to 1.

+

size - Integer or a SequenceableCollection of such, causing multichannel expansion. 

+

Determines the size of the returned multichannel envelope signal.

+

Not modulatable. Defaults to 2.

+

bus - Bus, bus index or a SequenceableCollection of such, causing multichannel expansion. 

+

Determines whether a private multichannel bus should be used for channel switching.

+

This is recommended for larger width sizes (> 10 or so) as otherwise the number of ugens 

+

might result in an overflow error.

+

Not modulatable. Defaults to nil.

+

zeroThr - A Number or a ugen returning zeroThr numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

Determines if output values below this threshold are replaced by 0.

+

This makes sense if the output signal is used as trigger (e.g. with DXEnvFan).

+

In the case of low power numbers small inaccuracies are amplified, this is avoided

+

with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power.

+

As this requires more ugens running in parallel it is disabled by default = nil.

+

doneAction - Integer or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the doneAction after maxFadeNum is exceeded.

+

Defaults to 0.

+


+

*kr (out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0)

+

+


+

+


+

Examples

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.reboot;

+

)

+

+


+

Ex.1) Basic types of crossfades

+


+

// For normal crossfades the default values - equal power panning of sine type - should be fine,

+

// other types of crossfade envelopes can be taken for other purposes such as granular synthesis.

+


+


+

// default width 2, default equal power crossfading

+


+

// employs crossfading from PanAz, which results in envelopes of sine type, from which

+

// the square root is taken

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// when dropping equalPower we get the pure sine envelope

+

// higher width

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

maxWidth: 8,

+

width: 5.5,

+

equalPower: 0,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// type sine = 0 switches to a linear curve base,

+

// with default equalPower = 1 this leads to a square root envelope

+


+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

sine: 0,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// a linear curve base without equalPower means a linear crossfade

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

sine: 0,

+

equalPower: 0,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// if equalPower is set to 0 you can choose a power

+

// check alternative values for sine and power also

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

equalPower: 0,

+

sine: 0,  // 1

+

power: 3, // 0.3

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// power can be a ugen too

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

equalPower: 0,

+

sine: 1,  // 1

+

power: SinOsc.ar(10, -pi/2).range(0.5, 10),

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// if equalPower is set to 0 you can also choose a curve arg

+

// which is passed as curvature to lincurve

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

equalPower: 0,

+

curve: 3,  // -3

+

sine: 0,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// curve can be a ugen too

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

curve: Line.ar(5, -5, 0.1),  // -3

+

sine: 0,

+

equalPower: 0,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// Passing a dynOutOffset arg - wobbled sliding

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

dynOutOffset: SinOsc.ar(150).range(0, 1),

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// This is not recommended:

+

// With dynOutOffset or modulated width a curve arg leads to irregularities

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

dynOutOffset: SinOsc.ar(150).range(0, 1),

+

equalPower: 0,

+

curve: 1,

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// out can also be a ugen, but note that with equalPower (default)

+

// blending the same channel leads to amplitude pikes,

+

// to avoid that take a linear crossfade

+


+

(

+

{

+

DXEnvFan.ar(

+

LFDNoise3.ar(15).range(0, 7),

+

size: 8,

+

fadeTime: 0.01,

+

stepTime: 0.02,

+

fadeMode: 1,

+

sine: 0, 

+

equalPower: 1  // compare 0

+

)

+

}.plot(1)

+

)

+


+


+

Ex.2) Sequencing crossfade types and parameters

+


+

// sequencing crossfade types and parameters must be allowed explicitely as 

+

// it is more CPU-costy

+


+

// alternate linear and pure sine

+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

allowTypeSeq: 1,

+

sine: Dseq([0, 1], inf),

+

equalPower: 0, // Dseq([0, 1], inf)

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+

// curvature sequencing

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

allowTypeSeq: 1,

+

sine: 0,

+

equalPower: 0, 

+

curve: Dseq([-3, -3, 3, 3], inf),

+

// fadeMode: 1,

+

// stepTime: 0.015

+

)

+

}.plot(0.1)

+

)

+


+


+Ex.3) The 'zeroThr' arg

+


+

// There might occur small inaccuracies in the calculation of crossfade values.

+

// This is irrelevant in most cases, but if you use the output signal as trigger

+

// it is definitely unwanted.

+

// You can supress such if you set an appropriate zero threshold.

+


+


+

// The effect of unwanted envelope segments especially becomes apparent

+

// with small power values that blow up values near 0.

+

// Values below the zeroThr are set to 0 before applying power or curvature.

+


+

// Compare version without passing zeroThr.

+


+

(

+

{

+

DXEnvFan.ar(

+

Dseq([3,2,1,4,5,6,7,0], inf),

+

size: 8,

+

fadeTime: 0.01,

+

equalPower: 0,

+

sine: 0,

+

power: 0.3,

+

fadeMode: 1,

+

stepTime: 0.015,

+

zeroThr: 0.002

+

)

+

}.plot(0.3)

+

)

+


+


+


+

Ex.4) The 'bus' arg

+


+

// As channel switching with DXEnvFan / DXFan is implemented by "watcher ugens",

+

// it becomes costy if the number of output channels increases (growth of quadratic order).

+

// The effort is lowered significantly if you pass a reserved bus for this or use DXEnvFanOut,

+

// this also concerns DXFan / DXFanOut.

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numPrivateAudioBusChannels = 256;

+

s.options.memSize = 8192 * 4;

+

s.options.numWireBufs = 512;

+

s.reboot;

+

)

+


+


+

// on my machine this example needs ca. 2.5 % CPU (818 ugens) ...

+


+

(

+

x = {

+

    DXEnvFan.ar(

+

        Dshuf((0..29), inf),

+

        size: 30,

+

        fadeTime: 0.005

+

    ) * 0.25

+

}.play

+

)

+


+

x.release

+


+

// ... whereas this needs ca. 0.6 % CPU (167 ugens)

+


+

(

+

a = Bus.audio(s, 30);

+


+

x = {

+

    DXEnvFan.ar(

+

        Dshuf((0..29), inf),

+

        size: 30,

+

        fadeTime: 0.005,

+

        bus: a

+

    ) * 0.25

+

}.play

+

)

+


+

x.release

+


+

(

+

a.free;

+

b.free;

+

)

+


+


+


+

// care has to be taken with buses and multichannel expansion:

+


+

// here two buses have to passed as otherwise we get a wrong result,

+

// the same bus would be taken for different calculations at the same time

+


+

(

+

a = Bus.audio(s, 8);

+

b = Bus.audio(s, 8);

+


+

{

+

Mix(DXEnvFan.ar(

+

[Dseq((0..7), inf), Dseq((7..0), inf)],

+

size: 8,

+

fadeTime: 0.01,

+

equalPower: 0,

+

bus: [a, b]

+

))

+

}.plot(0.1)

+

)

+


+

(

+

a.free;

+

b.free;

+

)

+


+


+


+

Ex.5) PlayBuf crossfading

+


+

// Here a two channel envelope signal is used to crossfade between

+

// two channels of a PlayBuf, as rates are close we get a trill effect.

+


+

// Note that the envelope signal is used three times:

+


+

// as a trigger to the startPos within PlayBuf

+

// as a trigger for the demand ugen that determines the startPos within PlayBuf

+

// as an envelope for the PlayBuf

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+

(

+

x = {

+

var sig, env = DXEnvFan.ar(

+

Dseq([0, 1], inf),

+

fadeMode: 3,

+

stepTime: 0.05,

+

fadeTime: 0.01,

+

// to ensure right triggering set zeroThr

+

zeroThr: 0.002

+

);

+


+

sig = PlayBuf.ar(

+

1,

+

b,

+

[1, 1.1] * BufRateScale.kr(b),

+

env,

+

Demand.ar(

+

env,

+

0,

+

Dstutter(

+

5,

+

Dwhite(0.1, 0.9)

+

) * BufFrames.ir(b)

+

)

+

) * 1.2 * env;

+

// do a bit correlation

+

Splay.ar(sig, 0.8)

+

}.play

+

)

+


+

x.release

+


+


+

// L and R get different mixes,

+

// both take the same envelope trigger which switches

+

// between PlayBufs of different rates, the difference between L and R

+

// comes from different random start positions.

+


+

(

+

x = {

+

var buf, env = DXEnvFan.ar(

+

Dseq([Dshuf((0..4)), Dshuf((5..7))], inf),

+

size: 8,

+

fadeMode: 3,

+

stepTime: 0.2,

+

fadeTime: 0.02,

+

zeroThr: 0.002

+

);

+


+

{ 

+

Mix(PlayBuf.ar(

+

1,

+

b,

+

{ |j| j / 4 + 0.3 } ! 8 * BufRateScale.kr(b),

+

env,

+

Demand.ar(env, 0, Drand((2..5)/10, inf) * BufFrames.ir(b)),

+

loop: 0,

+

) * env) 

+

} ! 2 ;

+

}.play

+

)

+


+


+

x.release

+


+

// variant with multichannel expansion

+

// two 8 ch trigger envelopes are used for L and R mixes

+

(

+

x = {

+

var buf, env = DXEnvFan.ar(

+

[Dseq((0..7), inf), Diwhite(0, 7)],

+

size: 8,

+

fadeMode: 3,

+

stepTime: 0.2,

+

fadeTime: 0.02,

+

zeroThr: 0.002

+

);

+


+

{ |i| Mix(PlayBuf.ar(

+

1,

+

b,

+

{ |j| j / 4 + 0.3 } ! 8 * BufRateScale.kr(b),

+

env[i],

+

// same positions go parallel

+

Demand.ar(env[i], 0, Dstutter(8, Dseq((2..5)/10, inf)) * BufFrames.ir(b)),

+

loop: 0,

+

) * env[i]) } ! 2 ;

+

}.play

+

)

+


+

x.release

+


+


+


+

Ex.6) Granulation, sequencing of fxs and fx parameters per grain

+


+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+

// sequencing of band pass frequency

+

// see also Buffer Granulation tutorial, Ex. 1f

+


+

(

+

a = Bus.audio(s, 8);

+


+

x = {

+

    var sig, env = DXEnvFan.ar(

+

        Dseq((0..7), inf),

+

        size: 8,

+

maxWidth: 8,

+

width: 5,

+

        fadeTime: 0.01,

+

        // to ensure right triggering set zeroThr

+

        zeroThr: 0.002,

+

        bus: a

+

    );

+


+

    sig = PlayBuf.ar(

+

        1,

+

        b,

+

        BufRateScale.kr(b),

+

        env,

+

        Demand.ar(env, 0, Dbrown(0.2, 0.5, 0.0025) * BufFrames.ir(b)),

+

        loop: 0,

+

    ) * env;

+

    

+

    // multichannel trigger polls from single sequencing source

+

// ensure non-zero filter freq for later triggers with max

+

sig = BPF.ar(sig, Demand.ar(env, 0, Dbrown(200, 2000, 100)).max(200), 0.1);

+


+

    // do a bit correlation

+

    Splay.ar(sig, 0.6) * 7

+

}.play

+

)

+


+

x.release

+


+

a.free

+


+


+

// sequencing of different fxs

+


+

(

+

a = Bus.audio(s, 8);

+


+

x = {

+

    var sig, env = DXEnvFan.ar(

+

        Drand((0..7), inf),

+

        size: 8,        

+

        maxWidth: 8,

+

        // oscillation of overlap

+

        width: LFDNoise3.ar(1).range(2, 6),

+

        fadeTime: 0.015,

+

        // to ensure right triggering set zeroThr

+

        zeroThr: 0.002,

+

        bus: a

+

    );

+


+

    sig = PlayBuf.ar(

+

        1,

+

        b,

+

        BufRateScale.kr(b),

+

        env,

+

        Demand.ar(env, 0, Dbrown(0.2, 0.5, 0.005) * BufFrames.ir(b)),

+

        loop: 0,

+

    ) * env;

+


+

    // selection of fxs as well as fx params triggered with envelope

+

    // ring modulation, bit crusher and band pass

+

    sig = Select.ar(Demand.ar(env, 0, Dstutter(Diwhite(5, 30), Dxrand([0, 1, 2], inf))), [

+

        sig * SinOsc.ar(Demand.ar(env, 0, Dbrown(250, 1000, 200))) * 1.5,

+

        sig.round(2 ** Demand.ar(env, 0, Dbrown(-1, -4, 1))).lag(0.005) * 1.5,

+

// ensure non-zero filter freq for later triggers with max

+

BPF.ar(sig, Demand.ar(env, 0, Dbrown(200, 2000, 200)).max(200), 0.2) * 5

+

    ]);

+


+

    // do a bit correlation

+

    Splay.ar(sig, 0.6)

+

}.play

+

)

+


+

x.release

+


+

a.free

+

 

+


+

Ex.7) Multichannel expansion

+


+


+

// Not as complicated options as with DXMix

+

// we get an array of multichannel envelopes, here a mix of them

+


+

(

+

{

+

Mix(DXEnvFan.ar(

+

(0..3).collect { |i| Dseq((0..3).rotate(i), inf) },

+

fadeTime: [0.01, 0.05],

+

size: 4,

+

width: 1

+

))

+

}.plot(0.2)

+

)

+


+

// see Ex.4 for a delicate case with bus args

+


+


+


+


+ + diff --git a/Help/DXEnvFanOut.html b/Help/DXEnvFanOut.html new file mode 100755 index 0000000..b0002e4 --- /dev/null +++ b/Help/DXEnvFanOut.html @@ -0,0 +1,283 @@ + + + + + + + + + + + +

DXEnvFanOut sends crossfade envelopes to out buses according to demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: AbstractDX

+


+

DXEnvFanOut sends multichannel envelopes, which are used by DXMix / DXMixIn / DXFan / DXFanOut implicitely, to a sequence of out buses, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. It can be used as envelope and trigger at the same time, which leads to applications such as crossfading PlayBufs and different kinds of granulation, using a buffer or not. 

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

See also: DX suite, DXMix, DXMixIn, DXEnvFan, DXFan, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

Creation / Class Methods

+


+

*ar (out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+

out - Determines the sequence of buses between which the envelope should be crossfaded.

+

A bus index, a demand rate or other ugen returning bus indices or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of out

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

fadeTime - A fade time, a demand rate or other ugens returning fade times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of fadeTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of fadeTime depends on fadeMode.

+

fadeTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

stepTime - A step time, a demand rate or other ugens returning step times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of stepTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of stepTime depends on fadeMode.

+

stepTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

fadeMode - Integers between 0 and 4 or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

fadeMode = 0: only fadeTimes are used, no steps

+

fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

Defaults to 0.

+

sine - Determines the crossfade type: sine-based or not.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning sine numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of sine

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

equalPower - Determines if crossfading of equal power type (square root) should be applied.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning equalPower numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of equalPower

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

power - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude. If power and curve are passed, power applies before.

+

A positive Number or a demand rate or other ugen returning positive power numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

curve - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude according to the lincurve mapping. 

+

If power and curve are passed, power applies before.

+

A Number or a demand rate or other ugen returning curve numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of curve

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Calculation of curvature is not giving reliable results when width and / or dynOutOffset are 

+

being modulated at the same time.

+

Defaults to 0. 

+

allowTypeSeq - Enables sequencing of sine, equalPower, power and curve with 

+

demand rate ugens and modulating of sine and equalPower with other ugens.

+

A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion.

+

Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0.

+

fadeRate - One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

Defaults to \ar.

+

maxFadeNum - Integer determining the maximum number of fades, after which doneAction applies. 

+

A SequenceableCollection causes multichannel expansion. Not modulatable.

+

Defaults to inf.

+

maxWidth - An Integer determining the maximum width or

+

a SequenceableCollection of such, causing multichannel expansion, width goes into PanAz's width arg.

+

maxWidth increases the internally used and potentially needed number of parallel channels. Not modulatable.

+

Determines the size of the returned multichannel signal.

+

Defaults to 2.

+

width - Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, 

+

causing multichannel expansion. Not modulatable in versions earlier than SC 3.9.

+

It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed maxWidth.

+

In case of  DXEnvFan's use as trigger you might want to set it really smaller than maxWidth.

+

Defaults to 2.

+

initOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines an initial offset for PanAz's pos arg.

+

This can be useful for a start with full or reduced width, see examples. 

+

Not modulatable. Defaults to 0.

+

maxDynOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the maximum dynOutOffset to be expected.

+

maxDynOutOffset increases the internally used and potentially needed number of parallel channels. 

+

Not modulatable. Defaults to 1.

+

dynOutOffset - UGen, Integer or Float or

+

a SequenceableCollection of such, causing multichannel expansion.

+

By passing a ugen the movement between buses can be modulated.

+

Note that a ugen's output must not exceed maxDynOutOffset.

+

Defaults to 0.

+

allowFadeEnd - Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion.

+

Determines if a demand rate input to out with finite length will be monitored, which needs a quite complicated 

+

trigger logic and more running ugens. If set to 0, the behaviour after the end of out is undefined.

+

Defaults to 1.

+

zeroThr - A Number or a ugen returning zeroThr numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

Determines if output values below this threshold are replaced by 0.

+

This makes sense if the output signal is used as trigger (e.g. with DXEnvFan).

+

In the case of low power numbers small inaccuracies are amplified, this is avoided

+

with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power.

+

As this requires more ugens running in parallel it is disabled by default = nil.

+

doneAction - Integer or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the doneAction after maxFadeNum is exceeded.

+

Defaults to 0.

+


+

*kr (out, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+


+

+


+

Examples

+


+

// NOTE: As with DXFan / DXFanOut examples from DXEnvFan help also can be written with DXEnvFanOut,

+

// but the latter doesn't need size and bus args as out buses are addressed directly.

+

// There is a small difference also with multichannel expansion, see last example below.

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.reboot;

+

)

+


+


+

Ex.1) Basic usage

+


+

// play SinOscs silently and wait for granulation envelopes

+


+

(

+

a = Bus.audio(s, 10);

+

x = { Splay.ar(In.ar(a, 10) * SinOsc.ar((3..12) * 100, 0, 0.05)) }.play

+

)

+


+


+

// send envelopes to buses

+


+

(

+

z = {

+

DXEnvFanOut.ar(

+

Dseq((0..5), inf) + Dwhite(1, 4) + a.index,

+

fadeTime: 0.05,

+

width: 1,

+

initOutOffset: -0.5

+

)

+

}.play

+

)

+


+

x.release;

+


+

// cleanup

+


+

(

+

z.free;

+

a.free;

+

)

+


+


+

Ex.2) Multichannel expansion

+


+


+

// play SinOscs silently and wait for granulation envelopes

+


+

(

+

a = Bus.audio(s, 10);

+

x = { Splay.ar(In.ar(a, 10) * SinOsc.ar((3..12) * 100, 0, 0.05)) }.play

+

)

+


+

// send envelope to buses in parallel

+


+

(

+

z = {

+

DXEnvFanOut.ar(

+

[0, 3] + Dseq((0..3), inf) + Dwhite(0, 3) + a.index,

+

fadeTime: 0.05,

+

width: 1,

+

initOutOffset: -0.5

+

)

+

}.play

+

)

+


+

x.release;

+


+

// cleanup

+


+

(

+

z.free;

+

a.free;

+

)

+


+


+

// Ex.7 from DXEnvFan help looks a bit different,

+

// as DXEnvFanOut is an out ugen we don't need to mix

+


+

(

+

a = Bus.audio(s, 4);

+

{

+

DXEnvFanOut.ar(

+

(0..3).collect { |i| Dseq((0..3).rotate(i), inf) } + a.index,

+

fadeTime: [0.01, 0.05],

+

width: 1

+

);

+

In.ar(a, 4)

+

}.plot(0.2)

+

)

+


+

a.free

+


+


+ + diff --git a/Help/DXFan.html b/Help/DXFan.html new file mode 100755 index 0000000..e88caa6 --- /dev/null +++ b/Help/DXFan.html @@ -0,0 +1,393 @@ + + + + + + + + + + + +

DXFan crossfades signals within a multichannel array according to demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: AbstractDX

+


+

DXFan crossfades signals to a sequence of channels, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. 

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

See also: DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

Creation / Class Methods

+


+

*ar (out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0)

+

+

out - Determines the sequence of channels between which the signal should be crossfaded.

+

A channel index, a demand rate or other ugen returning channel indices or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of out

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

channelsArrayRef - The signal to be crossfaded. 

+

A single channel can be passed as such, an array must be wrapped into a 

+

Ref object to avoid multichannel expansion.

+

In this case the multichannel signal is crossfaded from one block of adjacent channels to the next,

+

whereby the lowest channel index follows the base sequence defined by out.

+

A SequenceableCollection causes multichannel expansion, whereby single items of the collection

+

can itself be Ref objects containing multichannel signals.

+

fadeTime - A fade time, a demand rate or other ugens returning fade times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of fadeTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of fadeTime depends on fadeMode.

+

fadeTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

stepTime - A step time, a demand rate or other ugens returning step times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of stepTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of stepTime depends on fadeMode.

+

stepTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

fadeMode - Integers between 0 and 4 or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

fadeMode = 0: only fadeTimes are used, no steps

+

fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

Defaults to 0.

+

sine - Determines the crossfade type: sine-based or not.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning sine numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of sine

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

equalPower - Determines if crossfading of equal power type (square root) should be applied.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning equalPower numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of equalPower

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

power - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude. If power and curve are passed, power applies before.

+

A positive Number or a demand rate or other ugen returning positive power numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

curve - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude according to the lincurve mapping. 

+

If power and curve are passed, power applies before.

+

A Number or a demand rate or other ugen returning curve numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of curve

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Calculation of curvature is not giving reliable results when width and / or dynOutOffset are 

+

being modulated at the same time.

+

Defaults to 0. 

+

allowTypeSeq - Enables sequencing of sine, equalPower, power and curve with 

+

demand rate ugens and modulating of sine and equalPower with other ugens.

+

A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion.

+

Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0.

+

fadeRate - One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

Defaults to \ar.

+

maxFadeNum - Integer determining the maximum number of fades, after which doneAction applies. 

+

A SequenceableCollection causes multichannel expansion. Not modulatable.

+

Defaults to inf.

+

maxWidth - An Integer determining the maximum width or

+

a SequenceableCollection of such, causing multichannel expansion, width goes into PanAz's width arg.

+

maxWidth increases the internally used and potentially needed number of parallel channels. Not modulatable.

+

Defaults to 2.

+

width - Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, 

+

causing multichannel expansion. Not modulatable in versions earlier than SC 3.9.

+

It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed maxWidth.

+

Defaults to 2.

+

initOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines an initial offset for PanAz's pos arg.

+

This can be useful for a start with full or reduced width, see examples. 

+

Not modulatable. Defaults to 0.

+

maxDynOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the maximum dynOutOffset to be expected.

+

maxDynOutOffset increases the internally used and potentially needed number of parallel channels. 

+

Not modulatable. Defaults to 1.

+

dynOutOffset - UGen, Integer or Float or

+

a SequenceableCollection of such, causing multichannel expansion.

+

By passing a ugen the movement between channels can be modulated.

+

Note that a ugen's output must not exceed maxDynOutOffset.

+

Defaults to 0.

+

allowFadeEnd - Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion.

+

Determines if a demand rate input to out with finite length will be monitored, which needs a quite complicated 

+

trigger logic and more running ugens. If set to 0, the behaviour after the end of out is undefined.

+

Defaults to 1.

+

size - Integer or a SequenceableCollection of such, causing multichannel expansion. 

+

Determines the size of the returned multichannel signal.

+

Not modulatable. Defaults to 2.

+

bus - Bus, bus index or a SequenceableCollection of such, causing multichannel expansion. 

+

Determines whether a private multichannel bus should be used for channel switching.

+

This is recommended for larger width sizes (> 10 or so) as otherwise the number of ugens 

+

might result in an overflow error.

+

Not modulatable. Defaults to nil.

+

zeroThr - A Number or a ugen returning zeroThr numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

Determines if output values below this threshold are replaced by 0.

+

This makes sense if the output signal is used as trigger (e.g. with DXEnvFan).

+

In the case of low power numbers small inaccuracies are amplified, this is avoided

+

with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power.

+

As this requires more ugens running in parallel it is disabled by default = nil.

+

doneAction - Integer or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the doneAction after maxFadeNum is exceeded.

+

Defaults to 0.

+


+

*kr (out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, size = 2, bus = nil, zeroThr = nil, doneAction = 0)

+

+


+

+


+

Examples

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.reboot;

+

)

+


+

// Note that, as with DXEnvFan, higher values passed to 'size' and 'maxWidth'

+

// cause a significant growth of the number of used ugens.

+

// In this case consider passing a bus arg or the use of DXFanOut,

+

// see Ex.4 from DXEnvFan help.

+


+


+

Ex.1) Basic usage: simple crossfade

+

+

// crossfading a mono source between two outs

+


+

(

+

x = {

+

DXFan.ar(

+

Dseq([0, 1], inf),

+

PinkNoise.ar(0.05),

+

fadeTime: 1

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// Crossfading a stereo source between two outs,

+

// for more than two channels size has to be passed.

+


+

(

+

{

+

DXFan.ar(

+

Dseq([0, 2], inf),

+

`(Saw.ar(50 * [1, 5], 0.03)),

+

size: 4,

+

fadeTime: 0.1

+

)

+

}.plot(0.2)

+

)

+


+


+

// crossfading a mono source between several outs

+


+

(

+

{

+

DXFan.ar(

+

Dseq([0, 3, 1, 2], inf),

+

BPF.ar(PinkNoise.ar(), LFDNoise3.ar(1).range(100, 2000), 0.1, 0.7),

+

size: 4,

+

fadeTime: 0.05

+

)

+

}.plot(0.2)

+

)

+


+


+

// sliding over several channels, increased width

+


+

(

+

{

+

DXFan.ar(

+

Dseq([0, 3, 1, 2], inf),

+

BPF.ar(PinkNoise.ar(), LFDNoise3.ar(1).range(100, 2000), 0.1, 0.7),

+

size: 4,

+

fadeTime: 0.02,

+

maxWidth: 4,

+

width: 3

+

)

+

}.plot(0.2)

+

)

+


+


+

Ex.2) Multichannel expansion

+


+

// crossfading mono sources to alternate channels

+

// note that the result of DXFan, due to multichannel expansion, 

+

// is an array of two stereo arrays which is then mixed to one stereo array.

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

Mix(DXFan.ar(

+

[Dseq([0, 1], inf), Dseq([1, 0], inf)],

+

[

+

LFTri.ar(150 * lfo.().range(1, 2), 0, 0.05),

+

BPF.ar(PinkNoise.ar(), lfo.().range(1000, 3000), 0.1, 0.7)

+

],

+

fadeTime: 0.07,

+

width: 1

+

))

+

}.play

+

)

+


+

x.release

+


+


+

// crossfading stereo sources to channel pairs (4ch), polyrhythm of fadeTimes.

+

// Similar to the above example the result of DXFan, due to multichannel expansion, 

+

// is an array of two 4-channel arrays which is then mixed to one 4-channel array.

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

Mix(DXFan.ar(

+

[Dseq([0, 2], inf), Dseq([2, 0], inf)],

+

[

+

`({ |i| LFTri.ar(150 * lfo.().range(0.5, 2), 0, 0.05) } ! 2) ,

+

`({ |i| BPF.ar(PinkNoise.ar(), lfo.().range(500, 1500) * (i + 1), 0.1, 0.7) } ! 2)

+

],

+

size: 4,

+

fadeTime: [Dseq([0.06, 0.06, 0.03], inf), Dseq([0.05, 0.05, 0.17], inf)],

+

width: 1

+

))

+

}.play;

+

)

+


+

x.release

+


+


+

Ex.3) Granulation by crossfading to different channels

+


+

// mono source crossfaded to 8 channels

+


+

(

+

{

+

var lfo = LFDNoise3.kr(0.2);

+

DXFan.ar(

+

Dshuf((0..7), inf),

+

SinOsc.ar(lfo.range(800, 1500), 0, 0.03),

+

size: 8,

+

fadeTime: 0.01

+

)

+

}.plot(0.2)

+

)

+


+


+

// crossfading stereo pairs to every second out

+


+

(

+

{

+

var lfo = LFDNoise3.kr(0.2);

+

DXFan.ar(

+

Dseq((0, 2..6), inf),

+

`(SinOsc.ar(lfo.range(800, 1500) * [1, 1.02], 0, 0.03)),

+

size: 8,

+

fadeTime: 0.01

+

) ;

+

}.plot(0.2)

+

)

+


+


+

Ex.4) Granulation with high trigger rates and / or short grain durations

+


+


+

// fadeTimes should be above blockSize

+

// for shorter grains you can use smaller blocksizes

+


+

(

+

s.options.blockSize = 2;

+

s.reboot;

+

)

+


+

// as the effect is AM on single outs we get side bands

+


+

(

+

s.doWhenBooted {

+

x = {

+

var lfo = LFDNoise3.ar(0.2);

+

DXFan.ar(

+

Dseq((0..7), inf),

+

SinOsc.ar(lfo.range(800, 1500), 0, 0.03),

+

size: 8,

+

fadeTime: 0.0002

+

)

+

}.play

+

};

+

)

+


+

x.release

+


+


+

// go back to default

+


+

(

+

s.options.blockSize = 64;

+

s.reboot;

+

)

+


+


+ + diff --git a/Help/DXFanOut.html b/Help/DXFanOut.html new file mode 100755 index 0000000..4b4878b --- /dev/null +++ b/Help/DXFanOut.html @@ -0,0 +1,346 @@ + + + + + + + + + + + +

DXFanOut crossfades signals between out buses according to demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: AbstractDX

+


+

DXFanOut crossfades signals to a sequence of out buses, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. 

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

See also: DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

Creation / Class Methods

+


+

*ar (out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+

out - Determines the sequence of buses between which the signal should be crossfaded.

+

An out bus, a demand rate or other ugen returning out buses or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of out

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

channelsArrayRef - The signals to be crossfaded. 

+

A single channel doesn't can be passed as such, an array must be wrapped into a 

+

Ref object to avoid multichannel expansion.

+

In this case the multichannel signal is crossfaded from one block of adjacent buses to the next,

+

whereby the lowest bus index follows the base sequence defined by out.

+

A SequenceableCollection causes multichannel expansion, whereby single items of the collection

+

can itself be Ref objects containing multichannel signals.

+

fadeTime - A fade time, a demand rate or other ugens returning fade times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of fadeTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of fadeTime depends on fadeMode.

+

fadeTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

stepTime - A step time, a demand rate or other ugens returning step times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of stepTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of stepTime depends on fadeMode.

+

stepTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

fadeMode - Integers between 0 and 4 or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

fadeMode = 0: only fadeTimes are used, no steps

+

fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

Defaults to 0.

+

sine - Determines the crossfade type: sine-based or not.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning sine numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of sine

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

equalPower - Determines if crossfading of equal power type (square root) should be applied.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning equalPower numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of equalPower

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

power - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude. If power and curve are passed, power applies before.

+

A positive Number or a demand rate or other ugen returning positive power numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

curve - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude according to the lincurve mapping. 

+

If power and curve are passed, power applies before.

+

A Number or a demand rate or other ugen returning curve numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of curve

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Calculation of curvature is not giving reliable results when width and / or dynOutOffset are 

+

being modulated at the same time.

+

Defaults to 0. 

+

allowTypeSeq - Enables sequencing of sine, equalPower, power and curve with 

+

demand rate ugens and modulating of sine and equalPower with other ugens.

+

A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion.

+

Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0.

+

fadeRate - One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

Defaults to \ar.

+

maxFadeNum - Integer determining the maximum number of fades, after which doneAction applies. 

+

A SequenceableCollection causes multichannel expansion. Not modulatable.

+

Defaults to inf.

+

maxWidth - An Integer determining the maximum width or

+

a SequenceableCollection of such, causing multichannel expansion, width goes into PanAz's width arg.

+

maxWidth increases the internally used and potentially needed number of parallel channels. Not modulatable.

+

Defaults to 2.

+

width - Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, 

+

causing multichannel expansion. Not modulatable in versions earlier than SC 3.9.

+

It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed maxWidth.

+

Defaults to 2.

+

initOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determins an initial offset for PanAz's pos arg.

+

This can be useful for a start with full or reduced width, see examples. 

+

Not modulatable. Defaults to 0.

+

maxDynOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determins the maximum dynOutOffset to be expected.

+

maxDynOutOffset increases the internally used and potentially needed number of parallel channels. 

+

Not modulatable. Defaults to 1.

+

dynOutOffset - UGen, Integer or Float or

+

a SequenceableCollection of such, causing multichannel expansion.

+

By passing a ugen the movement between buses can be modulated.

+

Note that a ugen's output must not exceed maxDynOutOffset.

+

Defaults to 0.

+

allowFadeEnd - Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion.

+

Determines if a demand rate input to out with finite length will be monitored, which needs a quite complicated 

+

trigger logic and more running ugens. If set to 0, the behaviour after the end of out is undefined.

+

Defaults to 1.

+

zeroThr - A Number or a ugen returning zeroThr numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

Determines if output values below this threshold are replaced by 0.

+

This makes sense if the output signal is used as trigger (e.g. with DXEnvFan).

+

In the case of low power numbers small inaccuracies are amplified, this is avoided

+

with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power.

+

As this requires more ugens running in parallel it is disabled by default = nil.

+

doneAction - Integer or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the doneAction after maxFadeNum is exceeded.

+

Defaults to 0.

+


+

*kr (out, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+


+

+


+

Examples

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.reboot;

+

)

+


+


+

// NOTE: Examples from DXFan help also can be written with DXFanOut,

+

// DXFanOut doesn't need a size arg as the out bus is addressed directly.

+

// There is a small difference though with multichannel expansion, see example below.

+


+


+

Ex.1) Multichannel expansion

+


+

// Compare with Ex. 2 from DXFan help.

+

// As DXFanOut, other than DXFan, doesn't return an array, a mix is not necessary, 

+

// by internal use of Out ugens the signal is mixed to the referred buses anyway.

+


+

// For the same reason a normal release doesn't work, to get this option we can add an EnvGate.

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

DXFanOut.ar(

+

[Dseq([0, 1], inf), Dseq([1, 0], inf)],

+

[

+

LFTri.ar(150 * lfo.().range(1, 2), 0, 0.05),

+

BPF.ar(PinkNoise.ar(), lfo.().range(1000, 3000), 0.1, 0.7)

+

] * EnvGate(),

+

fadeTime: 0.07,

+

width: 1

+

)

+

}.play

+

)

+


+

x.release

+


+

+

Ex.2) Fast crossfading between fx processings ("fx granulation")

+


+

// To be distinguished by fx processing of grains!

+

// define fxs to read from buses

+


+

(

+

a = Bus.audio(s, 6);

+


+

SynthDef(\resample, { |out = 0, in, lfoFreq = 0.2, resampleLo = 500, resampleHi = 2000,

+

lag = 0.001, mix = 1, amp = 0.1|

+

var sig, inSig = In.ar(in, 2), lfo;

+

lfo = LFDNoise3.kr(lfoFreq).range(resampleLo, resampleHi);

+

sig = Latch.ar(inSig, Impulse.ar(lfo)).lag(lag);

+

    Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp);

+

}).add;

+


+

SynthDef(\ring, { |out = 0, in, lfoFreq = 0.2, modFreqLo = 50, modFreqHi = 2000,

+

mix = 1, amp = 0.1|

+

var sig, mod, lfo, src, inSig = In.ar(in, 2);

+

lfo = LFDNoise3.kr(lfoFreq).range(modFreqLo, modFreqHi);

+

mod = SinOsc.ar(lfo);

+

sig = inSig * mod;

+

Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp);

+

}).add;

+


+

SynthDef(\rectifier, { |out = 0, in, amount = 0, mix = 1, amp = 0.1|

+

var sig, inSig = In.ar(in, 2);

+

// need collect as if ugen doesn't take arrays

+

sig = inSig.collect { |x,i| x.ceil.if(x, x.abs * amount) };

+

   Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp);

+

}).add;

+

)

+


+

// start fxs first

+

(

+

u = Synth(\resample, [in: a.subBus(0, 2)]);

+

v = Synth(\ring, [in: a.subBus(2, 2)]);

+

w = Synth(\rectifier, [in: a.subBus(4, 2)]);

+

)

+


+


+

// start source, crossfade between fx buses

+

// play with MouseX, fx and source period are in integer relation

+


+

(

+

x = {

+

var seq = Demand.kr(

+

Impulse.kr(5),

+

0,

+

Dxrand([60, 62, 65.5, 66, 68.5], inf) + Drand([-12, 0, 12], inf)

+

).midicps.lag(0.015);

+


+

DXFanOut.ar(

+

Dseq([0, 1, 2], inf) * 2 + a.index,

+

`(SinOsc.ar(

+

seq * [1, 1.01],

+

0,

+

1

+

) * EnvGate()),

+

fadeTime: 0.2 / (MouseX.kr(5, 25).round.poll),

+

width: 1.2

+

)

+

}.play

+

)

+


+


+

// cleanup

+


+

x.release;

+


+

[u, v, w].do(_.free);

+


+


+


+

// granulated source + fast fx crossfades

+


+

// load sound file

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+


+

// start fxs first

+

(

+

u = Synth(\resample, [in: a.subBus(0, 2), lag: 0.01, mix: 0.6]);

+

v = Synth(\ring, [in: a.subBus(2, 2), mix: 1]);

+

)

+


+

// feed DXFanOut with granulated signal

+

// control two trigger rates with MouseX and MouseY

+

(

+

x = {

+

var trig = Impulse.ar(MouseY.kr(20, 100).poll(2, label: 'source trigrate'));

+

var pos = BufDur.kr(b) * LFDNoise3.ar(0.6).range(0.1, 0.5);

+

var sig = TGrains.ar(2, trig, b, 1, pos, 0.5, Dseq([-1, 1], inf) * 0.8, 3);

+

DXFanOut.ar(

+

Dseq([0, 2], inf) + a.index,

+

`(sig * EnvGate()),

+

fadeTime: 0.2 / (MouseX.kr(5, 100).round.poll(2, label: 'fx trigrate')),

+

width: 1.5

+

)

+

}.play

+

)

+


+

// cleanup

+


+

x.release;

+


+

[u, v].do(_.free);

+


+

a.free;

+


+


+ + diff --git a/Help/DXMix.html b/Help/DXMix.html new file mode 100755 index 0000000..f92bc17 --- /dev/null +++ b/Help/DXMix.html @@ -0,0 +1,1036 @@ + + + + + + + + + + + +

DXMix crossfades between signals according to demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: AbstractDX

+


+

DXMix crossfades between signals according to a sequence of indices, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. 

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

See also: DX suite, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut , Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

Creation / Class Methods

+


+

*ar (in, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+

in - Determines the sequence of signals to be crossfaded.

+

A demand rate or other ugen returning channel array indices, a single channel array index or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of in

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

channelsArrayRef - The signals to be crossfaded. 

+

To avoid multichannel expansion of this arg, the signals to be crossfaded must be wrapped into a Ref object.

+

If the Ref object contains an array of signal arrays, these arrays are crossfaded.

+

A SequenceableCollection causes multichannel expansion, whereby single items of the collection

+

can itself be Ref objects containing multichannel signals.

+

See multichannel examples below.

+

fadeTime - A fade time, a demand rate or other ugens returning fade times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of fadeTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of fadeTime depends on fadeMode.

+

fadeTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

stepTime - A step time, a demand rate or other ugens returning step times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of stepTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of stepTime depends on fadeMode.

+

stepTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

fadeMode - Integers between 0 and 4 or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

fadeMode = 0: only fadeTimes are used, no steps

+

fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

Defaults to 0.

+

sine - Determines the crossfade type: sine-based or not.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning sine numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of sine

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

equalPower - Determines if crossfading of equal power type (square root) should be applied.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning equalPower numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of equalPower

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

power - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude. If power and curve are passed, power applies before.

+

A positive Number or a demand rate or other ugen returning positive power numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

curve - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude according to the lincurve mapping. 

+

If power and curve are passed, power applies before.

+

A Number or a demand rate or other ugen returning curve numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of curve

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Calculation of curvature is not giving reliable results when width and / or dynOutOffset are 

+

being modulated at the same time.

+

Defaults to 0. 

+

allowTypeSeq - Enables sequencing of sine, equalPower, power and curve with 

+

demand rate ugens and modulating of sine and equalPower with other ugens.

+

A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion.

+

Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0.

+

fadeRate - One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

Defaults to \ar. 

+

maxFadeNum - Integer determining the maximum number of fades, after which doneAction applies. 

+

A SequenceableCollection causes multichannel expansion. Not modulatable.

+

Defaults to inf.

+

maxWidth - An Integer determining the maximum width or

+

a SequenceableCollection of such, causing multichannel expansion, width goes into PanAz's width arg.

+

maxWidth increases the internally used and potentially needed number of parallel channels. Not modulatable.

+

Defaults to 2.

+

width - Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, 

+

causing multichannel expansion. Not modulatable in versions earlier than SC 3.9.

+

It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed maxWidth.

+

Defaults to 2.

+

initOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines an initial offset for PanAz's pos arg.

+

This can be useful for a start with full or reduced width. 

+

Not modulatable. Defaults to 0.

+

maxDynOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the maximum dynOutOffset to be expected.

+

maxDynOutOffset increases the internally used and potentially needed number of parallel channels. 

+

Not modulatable. Defaults to 1.

+

dynOutOffset - UGen, Integer or Float or

+

a SequenceableCollection of such, causing multichannel expansion.

+

By passing a ugen the movement between buses can be modulated.

+

Note that a ugen's output must not exceed maxDynOutOffset.

+

Defaults to 0.

+

allowFadeEnd - Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion.

+

Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated 

+

trigger logic and more running ugens. If set to 0, the behaviour after the end of in is undefined.

+

Defaults to 1.

+

zeroThr - A Number or a ugen returning zeroThr numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

Determines if output values below this threshold are replaced by 0.

+

This makes sense if the output signal is used as trigger (e.g. with DXEnvFan).

+

In the case of low power numbers small inaccuracies are amplified, this is avoided

+

with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power.

+

As this requires more ugens running in parallel it is disabled by default = nil.

+

doneAction - Integer or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the doneAction after maxFadeNum is exceeded.

+

Defaults to 0.

+


+

*kr (in, channelsArrayRef, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+


+

+


+

Examples

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.reboot;

+

)

+


+

Ex.1) Basic usage: simple crossfade

+

+


+

// crossfading between 2 mono sources

+

// the array of channels to crossfade must be put into a Ref

+


+

(

+

x = {

+

DXMix.ar(

+

Dseq([0, 1], inf),

+

`[

+

Saw.ar(LFDNoise3.kr(0.1).range(40, 90), 0.03),

+

PinkNoise.ar(0.05)

+

],

+

fadeTime: 3

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// sources can itself be multichannel arrays

+

// fadeTimes passed as demand rate ugen

+


+

(

+

x = {

+

var lfo = LFDNoise3.kr(0.2);

+

DXMix.ar(

+

Dseq([0, 1], inf),

+

`[

+

Saw.ar(lfo.range(40, 90) * [1, 1.02], 0.03),

+

{ BPF.ar(PinkNoise.ar(0.05), lfo.range(200, 5000), 0.1) } ! 2

+

],

+

fadeTime: Dwhite(3, 7)

+

)

+

}.play

+

)

+


+

x.release

+


+


+


+

// So far all examples default to width = 2, PanAz's default width.

+

// It means that at most two channels overlap during crossfade.

+


+

// If higher values of width should be taken, maxWidth must be increased,

+

// in order to ensure a sufficiently large number of channels used for overlapping internally.

+

// See Ex.3 for a detailled explanation of the width arg.

+


+

// sliding over a sequence of channel indices

+


+

(

+

x = {

+

var lfo = LFDNoise3.kr(0.2);

+

DXMix.ar(

+

Dseq([0, 2, 1, 3], inf),

+

`[

+

Saw.ar(lfo.range(40, 70) * [1, 1.02], 0.02),

+

{ BPF.ar(PinkNoise.ar(0.05), lfo.range(200, 5000), 0.1) } ! 2,

+

Pulse.ar(lfo.range(40, 70) * [1, 1.02], 0.5, 0.02),

+

{ BPF.ar(Dust.ar(100), lfo.range(200, 5000), 0.1) } ! 2

+

],

+

fadeTime: Dwhite(3, 7),

+

maxWidth: 5,

+

width: 4

+

)

+

}.play

+

)

+


+

x.release

+


+


+


+


+

Ex.2) Basic usage: fades and steps

+

+


+

// in Ex. 1 we always used fadeMode's default 0, where only fades are polled

+

// You might instead want to alternate steps (sections of no fade) with fades:

+


+

// fadeMode = 0: only fadeTimes are used, no steps

+

// fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

// fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

// fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

// thus stepTime must be larger than fadeTime

+

// fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

// thus stepTime must be larger than fadeTime

+


+


+

// Check different fadeModes here, different effects with same times:

+


+

// With fadeMode = 2 or 4 we start with a short fade, which gives the impression of a pickup.

+

// With fadeMode = 3 or 4 the tempo is faster, as fadeTime is subtracted from stepTime.

+

// With these modes it's the user's responsibility to limit fadeTimes.

+


+


+

// NOTE: fadeTimes and stepTimes must be larger than the duration of a control cycle

+

// with default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec.

+

// If you go below, the step mechanism is messed up you get jumps and clicks.

+


+

// Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime,

+

// which is calculated by stepTime - fadeTime, is larger than this threshold.

+


+

(

+

x = {

+

DXMix.ar(

+

Dxrand((0..19), inf),

+

`(Saw.ar((1..10) * 100, 0.1) ++ SinOsc.ar((1..10) * 200, 0, 0.15)),

+

fadeTime: 0.05,

+

stepTime: 0.15,

+

fadeMode: 1

+


+

// check other fadeModes

+


+

// fadeMode: 2

+

// fadeMode: 3

+

// fadeMode: 4

+

)

+

// short fade-in with Function.play to make initial DXMix fade (fadeModes 2 and 4) audible

+

}.play(fadeTime: 0.005)

+

)

+


+

x.release

+


+


+

// some overtone fun with large width, independant DXMixs for L and R

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

{ 

+

DXMix.ar(

+

Dxrand((0..15), inf),

+

`(Saw.ar((1..8) * 70 * lfo, 0.05) ++ SinOsc.ar((1..8) * 68.5 * lfo, 0, 0.075)),

+

fadeTime: 0.02,

+

stepTime: 0.18,

+

fadeMode: 1,

+

width: 7,

+

maxWidth: 8

+

) 

+

} ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// ugen arguments can also be passed to 'in'

+

// the 'initOutOffset' arg is explained along the next examples

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

{ 

+

DXMix.ar(

+

LFDNoise3.ar(2).range(0, 15),

+

`(LFTri.ar((1..8) * 70 * lfo, 0, 0.05) ++ SinOsc.ar((1..8) * 68.5 * lfo, 0, 0.075)),

+

fadeTime: 0.01,

+

stepTime: 0.15,

+

fadeMode: 1,

+

width: 7,

+

maxWidth: 8,

+

equalPower: 0, // better here with sines, see curvature options in DXEnvFan help, Ex.1

+

initOutOffset: -4

+

) 

+

} ! 2

+

}.play

+

)

+


+

x.release

+


+


+


+

// stepTime controlled by ugen

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

{ 

+

DXMix.ar(

+

LFDNoise3.ar(2).range(0, 15),

+

`(LFTri.ar((1..8) * 70 * lfo, 0, 0.05) ++ SinOsc.ar((1..8) * 68.5 * lfo, 0, 0.075)),

+

fadeTime: 0.01,

+

stepTime: SinOsc.ar(0.2).range(0.1, 0.5),

+

fadeMode: 1,

+

width: 3,

+

maxWidth: 8,

+

initOutOffset: -3

+

) 

+

} ! 2

+

}.play

+

)

+


+

x.release

+


+


+


+

Ex.3) Width and offset arguments for channel span

+


+

// The width parameter determines the number of channels, which are 

+

// maximally affected by the crossfade, it uses the convention of PanAz's width arg. 

+

// The graphics below explain the overlap scheme of DXMix and cousins,

+

// for DXMix the indices denote the channels to be mixed,

+

// for DXMixIn the indices denote the buses to be mixed,

+

// for DXFanOut the buses to which the signal will be spread,

+

// for DXFan the channels to which the signal will be spread,

+

// for DXEnvFanOut the buses to which the envelope will be spread.

+

// for DXEnvFan the channels to which the envelope will be spread.

+


+

// Let's look at a DXMix example with different width values:

+


+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf),

+

`(Saw.ar((1..8) * 70 * lfo, 0.075)),

+

fadeTime: 0.12,

+

stepTime: 0.38,

+

fadeMode: 1,

+

width: 2,

+

// check other width values below maxWidth

+


+

maxWidth: 8

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+

// Width = 2 means that the crossfade only affects adjacent channels / signals / buses. 

+

// In the graphic the center position of the movement is marked with bold letters, 

+

// a diamond sign denotes, that the center lies in the middle of two channels, 

+

// which are then equally weighted. Squared brackets enclose the active channel numbers.

+

// So the succession of two rows describes one fade.

+


+

// width = 2:

+


+

+


+

// For an arbitrary integer width n the number of active channels lies between n-1 and n, 

+

// here a scheme of the number of affected channels:

+


+


+

width number of channels affected with

+

center position directly at channel

+


+

2 1

+

3 3

+

4 3

+

5 5

+

6 5

+

7 7

+

8 7

+

...

+


+

width number of channels affected with

+

center position exactly between two channels

+


+

2 2

+

3 2

+

4 4

+

5 4

+

6 6

+

7 6

+

8 8

+

...

+


+


+

// DXMix and cousins take over the logic of PanAz. However there's a little difference at 

+

// start with width > 2. As we are sliding over a index sequence which has a beginning, 

+

// it seems natural that the start index should be the middle of the span, which is covered according to width. 

+

// So from width > 2 onwards there's a "left side" of the channel span, which hasn't been generated so far, 

+

// thus the full width is not reached before an entrance phase which increases with the width value.

+


+

// width = 3:

+


+

+


+


+

// width = 4:

+


+

+


+


+

// If one wants to start width full width there's the possibility to do this by 

+

// passing an initOutOffset argument.

+


+

// Here we start with initOutOffset = 1, fadeMode = 1 (step first),

+

// index = 4 (5th partial) is the middle of the channel span with most weight,

+

// which can be clearly perceived.

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf),

+

`(Saw.ar((1..8) * 70 * lfo, 0.075)),

+

fadeTime: 0.1,

+

stepTime: 2,

+

fadeMode: 1,

+

width: 3,

+

maxWidth: 8,

+

initOutOffset: 1

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// overlap scheme with width = 3 and initOutOffset = 1:

+


+

+


+


+

// Here we start with initOutOffset = 0.5, fadeMode = 1 (step first),

+

// channels with indices 0 and 4 (base tone and 5th partial) are equally weighted.

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf),

+

`(Saw.ar((1..8) * 70 * lfo, 0.075)),

+

fadeTime: 0.1,

+

stepTime: 2,

+

fadeMode: 1,

+

width: 3,

+

maxWidth: 8,

+

initOutOffset: 0.5

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// overlap scheme with width = 3 and initOutOffset = 0.5:

+


+


+

+


+


+


+

// It might also be desirable to start with a fade from silence.

+

// This can be done with a negative initOutOffset:

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf),

+

`(Saw.ar((1..8) * 70 * lfo, 0.075)),

+

fadeTime: 2,

+

width: 2,

+

initOutOffset: -1

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// overlap scheme with width = 2 and initOutOffset = -1:

+


+


+

+


+


+


+

// width can also be modulated (suited rather for lfos, only enabled from SC 3.9 onwards)

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf),

+

`(Saw.ar((1..8) * 70 * lfo, 0.05)),

+

fadeTime: 2,

+

width: SinOsc.ar(LFDNoise3.ar(1).range(0.2, 10)).range(2, 5),

+

maxWidth: 5

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// for faster modulations take dynOutOffset,

+

// maxDynOutOffset must be set properly

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

{ 

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf),

+

`(SinOsc.ar((1..8) * 140 * lfo, 0, 0.05)),

+

fadeTime: 2,

+

width: 2,

+

maxDynOutOffset: 2,

+

dynOutOffset: SinOsc.ar(LFDNoise3.ar(1).range(0.2, 25)).range(0, 2)

+

) 

+

} ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// You can also control the movement of the channel span entirely by 

+

// passing a ugen to dynOutOffset, therefore set fadeTime to inf. 

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

{ 

+

DXMix.ar(

+

Dseq([0, 4, 1, 5, 2, 6, 3, 7, 0], inf),

+

`(SinOsc.ar((1..8) * 140 * lfo, 0, 0.05)),

+

fadeTime: inf,

+

width: 2,

+

maxDynOutOffset: 7,

+

dynOutOffset: SinOsc.ar(0.2).range(0, 7)

+

) 

+

} ! 2

+

}.play

+

)

+


+

x.release

+


+


+

Ex.4) Switching between PlayBufs

+


+

// This can go towards granulation

+


+

// load sound file

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+


+

// switch between looping PlayBufs

+


+

(

+

x = {

+

var sig = {

+

DXMix.ar(

+

Dxrand([0, 1, 2], inf),

+

`(PlayBuf.ar(1, b, BufRateScale.kr(b) * [0.4, 1, 2.2], loop: 1)),

+

stepTime: 0.2,

+

fadeTime: 0.01,

+

fadeMode: 1,

+

width: 2

+

) } ! 2;

+

// do a bit correlation

+

Splay.ar(sig, 0.8)

+

}.play

+

)

+


+

x.release

+


+


+

Ex.5) Granulation

+


+


+

// granulation by fast fading between channels

+

// here single channels contain PlayBufs with ordered rates

+


+

// load sound file

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+


+

// widths (default 2) means overlap, thus grain length = 0.02

+


+

(

+

x = {

+

    var durs, trig, sig, thr = 0.5;

+

    sig = { |i|

+

        DXMix.ar(

+

            Dseq((49..0), inf),

+

            `(PlayBuf.ar(

+

                    1,

+

                    b,

+

                    BufRateScale.kr(b) * ({ |j| j / 500 + 0.7 + (i * 0.02) } ! 50),

+

                    loop: 1

+

                )),

+

            fadeTime: 0.01

+

        )

+

    } ! 2;

+

    // do a bit correlation

+

    Splay.ar(sig, 0.8)

+

}.play

+

)

+


+

x.release

+


+


+

// microsound with synthesized sources

+

// fadeTime change between very fast and medium length

+


+

// compare version with dynOutOffset

+


+

(

+

// universal lfo, several instances to be used, thus put into a Function

+


+

l = { LFDNoise3.ar(LFDNoise3.ar(1).exprange(0.1, 30)).range(0.5, 3) };

+


+

// pool of sources and arguments for channel array

+


+

e = (

+

GrayNoise: [0.1],

+

Dust: [500],

+

BrownNoise: [0.1],

+

Pulse: [exprand(50, 500) * l],

+

SinOsc: [exprand(50, 500) * l],

+

Saw: [exprand(50, 500) * l]

+

);

+


+

x = {

+

var durs, trig, sig, thr = 0.5;

+

sig = { |i|

+

DXMix.ar(

+

Dseq((0..19), inf),

+

`(

+

// generate array of oscillators to slide over

+

{

+

var sym = e.keys.choose;

+

sym.asClass.performList(\ar, e[sym]);

+

} ! 20

+

),

+

fadeTime: Dstutter(

+

Diwhite(2, 5),

+

Dwhite(0.01, 1).linexp(0.01, 1, 0.01, 1)

+

),

+

width: 2,

+

maxWidth: 2,

+

// add oscillation between adjacent channels of sequence

+

// dynOutOffset: SinOsc.ar(LFDNoise3.ar(1).exprange(1, 100)).range(0, 1)

+

) * 0.1

+

} ! 2;

+

// do a bit correlation

+

Splay.ar(sig, 0.8) * 2

+

}.play

+

)

+


+


+

x.release

+


+


+

Ex.6) Multichannel expansion

+


+

// If a multiple demand rate ugen is implicitely needed, it must be wrapped into a Function

+


+

// Because of the array passed to fadeTime, we need two Dseqs to poll from.

+

// As only one demand rate ugen is passed as 'in' arg, it must be wrapped into a Function.

+


+

(

+

x = {

+

DXMix.ar(

+

{ Dseq([0, 1, 2], inf) },

+

// equivalent:

+

// [Dseq([0, 1, 2], inf), Dseq([0, 1, 2], inf)],

+

`[

+

Saw.ar(LFDNoise3.kr(0.1).range(40, 90), 0.03),

+

Pulse.ar(LFDNoise3.kr(0.1).range(80, 180), 0.5, 0.03),

+

PinkNoise.ar(0.05)

+

],

+

fadeTime: [0.03, 3]

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// L and R switching between same sources

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

DXMix.ar(

+

[Dseq([0, 1, 2], inf), Dseq([2, 3, 1], inf)],

+

`[

+

Saw.ar(lfo.().range(40, 90), 0.03),

+

BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1),

+

BPF.ar(Crackle.ar(1.95, 0.5), lfo.().range(200, 5000), 0.1),

+

Pulse.ar(lfo.().range(40, 90), 0.5, 0.03)

+

],

+

fadeTime: { Dwhite(3, 7) }

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// L and R switching between different sources

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

DXMix.ar(

+

[Dseq([0, 1], inf), Dseq([1, 0], inf)],

+

[

+

`[

+

Saw.ar(lfo.().range(40, 90), 0.03),

+

BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1)

+

],

+

`[

+

Saw.ar(lfo.().range(40, 90), 0.03),

+

BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1)

+

]

+

],

+

fadeTime: { Dwhite(3, 7) }

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// last example, written in a more condensed way

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

DXMix.ar(

+

[Dseq([0, 1], inf), Dseq([1, 0], inf)],

+

[

+

{ Saw.ar(lfo.().range(40, 90), 0.03) } ! 2,

+

{ BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1) } ! 2

+

].flop.collect(`_),

+

fadeTime: { Dwhite(3, 7) }

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// overtone series - L up, R down

+

// decreasing fundamental 

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

DXMix.ar(

+

[Dseq((0..15), inf), Dseq((15..0), inf)],

+

`(SinOsc.ar((1..16) * 120 * lfo, 0, 0.05)),

+

fadeTime: 0.1,

+

equalPower: 0

+

)

+

}.play

+

)

+


+

x.release

+


+


+


+

// more complicated expansions:

+

// DXMix produces a nested array of two stereo fades,

+

// it is mixed to a flat stereo array

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

Mix(DXMix.ar(

+

[Dseq([0, 1], inf), Dseq([2, 3], inf)],

+

`[

+

Saw.ar(lfo.().range(40, 90) * [1, 3], 0.03),

+

{ BPF.ar(BrownNoise.ar(0.05), lfo.().range(100, 500), 0.3) } ! 2,

+

SinOsc.ar(lfo.().range(200, 500) * [2, 3], 0, 0.03),

+

{ BPF.ar(Dust.ar(300), lfo.().range(200, 5000), 0.1) } ! 2

+

],

+

fadeTime: [Dwhite(3, 7), Dwhite(2, 5)]

+

))

+

}.play

+

)

+


+

x.release

+


+


+

// similar situation as above, but the two stereo fades are referring to the same channels

+

// the result is a kind of accentuation

+


+

(

+

x = {

+

var lfo = LFDNoise3.kr(0.2);

+

Mix(DXMix.ar(

+

[Dseq([0, 1], inf), Dseq([1, 1, 1, 0], inf)],

+

`[

+

Saw.ar(lfo.range(40, 90) * [1, 3], 0.025),

+

{ BPF.ar(PinkNoise.ar(0.05), lfo.range(500, 5000), 0.1, 5) } ! 2

+

],

+

fadeTime: [Dwhite(3, 7), 0.1],

+

// width < 2 produces fade gaps

+

width: [2, 0.7]

+

))

+

}.play

+

)

+


+

x.release

+


+


+

// interesting multichannel expansions are possible with drate ugens based on nested arrays,

+

// e.g. coupling of streams 

+


+

(

+

x = {

+

var lfo = { LFDNoise3.kr(0.2) };

+

Mix(DXMix.ar(

+

Dxrand([[0, 1], [1, 0], [2, 3], [3, 2]], inf),

+

`[

+

Saw.ar(lfo.().range(40, 90) * [1, 3], 0.02),

+

{ BPF.ar(PinkNoise.ar(1), lfo.().range(500, 5000), 0.02, 1) } ! 2,

+

SinOsc.ar(lfo.().range(400, 900) * [1, 1.2], 0, 0.01),

+

{ BPF.ar(ClipNoise.ar(0.2), lfo.().range(500, 5000), 0.02, 1) } ! 2

+

],

+

fadeTime: 0.1,

+

// width < 2 produces fade gaps

+

width: 1

+

))

+

}.play

+

)

+


+

x.release

+


+


+

Ex.7) Stopping and doneAction

+


+

// The done action is invoked after maxFadeNum.

+


+

(

+

x = {

+

var lfo = LFDNoise3.kr(0.2);

+

DXMix.ar(

+

Dseq([0, 1], inf),

+

`[

+

Saw.ar(lfo.range(40, 90) * [1, 1.02], 0.03),

+

{ BPF.ar(PinkNoise.ar(0.05), lfo.range(200, 5000), 0.1) } ! 2

+

],

+

fadeTime: 0.5,

+

stepTime: 1,

+

fadeMode: 0, // check with other modes too

+

maxFadeNum: 5,

+

doneAction: 2

+

)

+

}.play

+

)

+


+

x.release

+


+


+

Ex.8) Saving CPU

+


+

// This might be a topic if you're running many fades in parallel and 

+

// fadeTimes are not extremely short (and hence audio rate doesn't make a difference).

+


+

// Here my machine needs ca. 2 % CPU for fadeRate = \kr

+

// and ca. 6 % CPU for fadeRate = \ar.

+


+

// 10 parallel sequences of overtone fading

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

var sig = DXMix.ar(

+

{ Drand((0..15), inf) },

+

`(SinOsc.ar((1..16) * 70 * lfo, 0, 0.2 / (1..16).sqrt)),

+

fadeTime: 1 / (1..10),

+

fadeRate: \kr,  // check CPU difference to \ar

+

maxWidth: 4,

+

width: 3

+

);

+

Splay.ar(sig)

+

}.play

+

)

+


+

x.release

+


+


+

// monitoring demand rate ugens needs a quite complicated trigger logic in this context

+

// per default you can pass finite drate ugens for 'in' - 

+

// observe that layers will stop after different times as fadeTimes are different

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

var sig = DXMix.ar(

+

{ Drand((0..15), 20) },

+

`(SinOsc.ar((1..16) * 70 * lfo, 0, 0.2 / (1..16).sqrt)),

+

fadeTime: 1 / (1..10),

+

fadeRate: \kr,  // also check CPU difference to \ar

+

maxWidth: 4,

+

width: 3

+

);

+

Splay.ar(sig)

+

}.play

+

)

+


+

x.release

+


+


+

// if you don't need this option you can save a number of ugens with allowFadeEnd = 0, compare

+


+

(

+

x = {

+

var lfo = XLine.ar(1, 0.5, 60);

+

var sig = DXMix.ar(

+

{ Drand((0..15), 20) },

+

`(SinOsc.ar((1..16) * 70 * lfo, 0, 0.2 / (1..16).sqrt)),

+

fadeTime: 1 / (1..10),

+

fadeRate: \kr,  // also check CPU difference to \ar

+

maxWidth: 4,

+

width: 3,

+

allowFadeEnd: 0

+

);

+

Splay.ar(sig)

+

}.play

+

)

+


+

x.release

+


+

// Also see Ex.2, Ex.4 from DXEnvFan help for CPU aspects.

+

// Note that the use of the options allowTypeSeq and zeroThr also needs more CPU.

+

// Rescaling, which is necessary for SC versions before 3.9 with audio rate, is also more CPU-costy.

+


+


+


+


+


+


+ + diff --git a/Help/DXMixIn.html b/Help/DXMixIn.html new file mode 100755 index 0000000..397d7bf --- /dev/null +++ b/Help/DXMixIn.html @@ -0,0 +1,286 @@ + + + + + + + + + + + +

DXMixIn crossfades between signals from buses according to demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: AbstractDX

+


+

DXMixIn crossfades between signals from buses according to a sequence of indices, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. 

+


+

NOTE: As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: DXMix - DXMixIn - DXEnvFan - DXEnvFanOut - DXFan - DXFanOut. Some general conventions are treated in detail in the following examples: fades and steps in DXMix help, Ex.2 – width and offset arguments in DXMix help, Ex.3 – multichannel expansion in DXMix help, Ex.6 – crossfade types in DXEnvFan help, Ex.1.

+


+

NOTE: PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice.

+


+

NOTE: Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See Ex.8 from DXMix help and Ex.2, Ex.4 from DXEnvFan help for aspects of CPU demand.

+


+

NOTE: In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See DXFan help Ex.4 for aspects of granulation with high trigger rates / short grain durations.

+


+

NOTE: The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours.

+


+

CREDITS: Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz.

+


+


+

See also: DX suite, DXMix, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut , Buffer Granulation, Live Granulation, PbindFx, kitchen studies, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

Creation / Class Methods

+


+

*ar (in, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+

in - Determines the sequence of signals to be crossfaded.

+

A demand rate or other ugen returning bus indices, a single bus index or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of in

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

fadeTime - A fade time, a demand rate or other ugens returning fade times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of fadeTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of fadeTime depends on fadeMode.

+

fadeTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

stepTime - A step time, a demand rate or other ugens returning step times or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of stepTime

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

The interpretation of stepTime depends on fadeMode.

+

stepTime must be larger than the duration of a control cycle.

+

Defaults to 1.

+

fadeMode - Integers between 0 and 4 or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

fadeMode = 0: only fadeTimes are used, no steps

+

fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade

+

fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade

+

fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step,

+

thus stepTime must be larger than fadeTime,

+

the difference must be larger than the duration of a control cycle

+

Defaults to 0.

+

sine - Determines the crossfade type: sine-based or not.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning sine numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of sine

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

equalPower - Determines if crossfading of equal power type (square root) should be applied.

+

A Boolean, 0 or 1 or a demand rate or other ugen returning equalPower numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of equalPower

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Modulating this arg is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

power - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude. If power and curve are passed, power applies before.

+

A positive Number or a demand rate or other ugen returning positive power numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Defaults to 1. 

+

curve - This only comes into play if equalPower equals 0, then it's applied to the 

+

crossfade amplitude according to the lincurve mapping. 

+

If power and curve are passed, power applies before.

+

A Number or a demand rate or other ugen returning curve numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

If in this case the overall multichannel size is larger than the size of curve

+

and the latter contains demand rate ugens, they must all be wrapped into Functions.

+

Sequencing this arg with demand rate ugens is only possible if allowTypeSeq equals 1.

+

Calculation of curvature is not giving reliable results when width and / or dynOutOffset are 

+

being modulated at the same time.

+

Defaults to 0. 

+

allowTypeSeq - Enables sequencing of sine, equalPower, power and curve with 

+

demand rate ugens and modulating of sine and equalPower with other ugens.

+

A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion.

+

Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0.

+

fadeRate - One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or

+

a SequenceableCollection of such, causing multichannel expansion. Not modulatable.

+

Defaults to \ar. 

+

maxFadeNum - Integer determining the maximum number of fades, after which doneAction applies. 

+

A SequenceableCollection causes multichannel expansion. Not modulatable.

+

Defaults to inf.

+

maxWidth - An Integer determining the maximum width or

+

a SequenceableCollection of such, causing multichannel expansion, width goes into PanAz's width arg.

+

maxWidth increases the internally used and potentially needed number of parallel channels. Not modulatable.

+

Defaults to 2.

+

width - Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, 

+

causing multichannel expansion. Not modulatable in versions earlier than SC 3.9.

+

It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed maxWidth.

+

Defaults to 2.

+

initOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines an initial offset for PanAz's pos arg.

+

This can be useful for a start with full or reduced width, see examples. 

+

Not modulatable. Defaults to 0.

+

maxDynOutOffset - An Integer or Float or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the maximum dynOutOffset to be expected.

+

maxDynOutOffset increases the internally used and potentially needed number of parallel channels. 

+

Not modulatable. Defaults to 1.

+

dynOutOffset - UGen, Integer or Float or

+

a SequenceableCollection of such, causing multichannel expansion.

+

By passing a ugen the movement between buses can be modulated.

+

Note that a ugen's output must not exceed maxDynOutOffset.

+

Defaults to 0.

+

allowFadeEnd - Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion.

+

Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated 

+

trigger logic and more running ugens. If set to 0, the behaviour after the end of in is undefined.

+

Defaults to 1.

+

zeroThr - A Number or a ugen returning zeroThr numbers or 

+

a SequenceableCollection of such, causing multichannel expansion.

+

Determines if output values below this threshold are replaced by 0.

+

This makes sense if the output signal is used as trigger (e.g. with DXEnvFan).

+

In the case of low power numbers small inaccuracies are amplified, this is avoided

+

with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power.

+

As this requires more ugens running in parallel it is disabled by default = nil.

+

doneAction - Integer or a SequenceableCollection of such, causing multichannel expansion.

+

Determines the doneAction after maxFadeNum is exceeded.

+

Defaults to 0.

+


+

*kr (in, fadeTime = 1, stepTime = 1, fadeMode = 0, sine = 1, equalPower = 1, power = 1, curve = 0, allowTypeSeq = 0, fadeRate = \ar, maxFadeNum = inf, maxWidth = 2, width = 2, initOutOffset = 0, maxDynOutOffset = 1, dynOutOffset = 0, allowFadeEnd = 1, zeroThr = nil, doneAction = 0)

+

+


+

+


+

Examples

+


+

(

+

// load with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.reboot;

+

)

+


+


+

Ex.1) Crossfaded mixing from buses

+

+


+

// play to buses silently

+


+

(

+

a = Bus.audio(s, 5);

+


+

x = {

+

Out.ar(a.index, [

+

BrownNoise.ar(0.1),

+

PinkNoise.ar(0.2),

+

WhiteNoise.ar(0.05),

+

ClipNoise.ar(0.03),

+

GrayNoise.ar(0.05)

+

])

+

}.play

+

)

+


+

// mix from buses, mind node order

+


+

(

+

y = {

+

DXMixIn.ar(

+

Dxrand((0..4), inf) + a.index,

+

fadeTime: 0.5,

+

)

+

}.play(addAction: \addToTail)

+

)

+


+

y.release

+


+


+

// cleanup

+


+

(

+

x.free;

+

a.free;

+

)

+


+


+


+


+

Ex.2) Multichannel expansion

+

+

// play to buses silently

+


+

(

+

a = Bus.audio(s, 5);

+

x = { Out.ar(a.index, SinOsc.ar((3..7) * 100, 0, 0.05)) }.play

+

)

+


+

// mix the source

+

// a Drate ugen with arrays causes multichannel expansion

+

// thus the drate ugen for fadeTime needs to be wrapped into a Function

+


+

(

+

z = {

+

DXMixIn.ar(

+

Drand([[0, 1], [2, 3], [4, 0], [1, 2], [3, 4]], inf) + a.index,

+

fadeTime: { Dwhite(0.5, 5) }

+

)

+

}.play(addAction: \addToTail)

+

)

+


+

// stop DXMixIn, source still running

+


+

z.release

+


+


+

// get source with other rhythm

+


+

(

+

z = {

+

DXMixIn.ar(

+

Dseq([[0, 1], [2, 3], [4, 0], [1, 2], [3, 4]], inf) + a.index,

+

fadeTime: [0.05, 2]

+

)

+

}.play(addAction: \addToTail)

+

)

+


+

z.release

+


+

// cleanup

+


+

(

+

x.free;

+

a.free;

+

)

+


+


+


+


+ + diff --git a/Help/Event patterns and Functions.html b/Help/Event patterns and Functions.html new file mode 100755 index 0000000..a52aea3 --- /dev/null +++ b/Help/Event patterns and Functions.html @@ -0,0 +1,338 @@ + + + + + + + + + + + +

Event patterns and Functions using event patterns with functional elements

+


+

Part of: miSCellaneous

+


+

See also: PLx suite, VarGui, VarGui shortcut builds, HS with VarGui

+


+


+

This is a tutorial file about event patterns with functional code. Features concerning scope are regarded along a line from Functions to Streams, Streams of Events and EventStreamPlayers. These general characteristics allow to generate a parametrized family of EventStreamPlayers from a single event pattern definition and are used as a base for controlling EventStreamPlayers with VarGui. For a convenience way to generate Patterns with environment-dependent reference see PLx suite.

+


+

Functions in Environments

+


+

Environments are a standard way to separate namespaces in SuperCollider. Functions may include environmental variables and then dynamic scope comes into play: variables get the value from the context in which the Function is evaluated. Anyway a specific environment can be linked with the Function, the latter will hold for Streams polled from Patterns with certain functional code    it's just the environment in which the stream has been generated from the pattern.

+


+

Take a simple Function with one argument and assign it to the interpreter variable f:

+


+

f = { |x| x*2 + ~a };

+


+

// equivalent:

+


+

f = { |x| x*2 + currentEnvironment[\a] };

+


+

// now set the variable in the Environment (context) in which to evaluate the Function later on

+


+

~a = 1;

+


+

// equivalent:

+

// currentEnvironment[\a] = 1;

+


+

// not surprising the result of the following operation:

+


+

f.value(1); 

+


+

// or shorter: 

+

// f.(1)

+


+

-> 3

+


+

// now evaluation in new environment, value taken from there:

+


+

(

+

e = Environment[\a -> 5];

+

e.use { f.value(1) };

+

)

+


+

-> 7

+


+

// with inEnvir a new Function is bound to a specific Environment

+


+

(

+

g = f.inEnvir(e);

+

g.(1);

+

)

+


+

-> 7

+


+


+

f.(1);

+


+

-> 3

+


+


+

So either by evaluating the original Function in different Environments or, equivalently, by deriving new Functions from the original attached to different Environments we create a parametrized family of Functions. The Function's basic behaviour is pretty simple (x*2), in dependance of the context it is just varied (a linear offset is added). With more environmental variables a much greater complexity could be introduced, though possibly obscuring the basic behaviour.

+


+

This priciple can now easily be extended to Streams, Streams of Events and EventStreamPlayers. We define the basic behaviour of an event stream with an event pattern (Pbind), then enrich the event pattern with functional code and can have a huge variety of EventStreamPlayers in different Environments with different parameter sets – all playable and modifiable in realtime (in parallel or independentely) and all polled from one single event pattern definition!  Step by step:

+


+


+

Streams in Environments

+


+

What happens in the case of a Stream that will repeatedly evaluate a Function?

+


+

// the Pfunc just describes what a Stream, polled from it, should do (evaluate a Function by the method next)

+

// the Pfunc itself is not bound to a specific Environment

+


+

p = Pfunc { ~a };

+


+

// by making a Stream an Environment (the current) is attached

+


+

(

+

q = p.asStream;

+

~a = 1;

+

q.next;

+

)

+


+

-> 1

+


+

// next value of (Func)Stream demanded in new Environment will be taken from old defining context 

+


+

(

+

~a = 2;

+

e = Environment[\a -> 5];

+

e.use { q.next };

+

)

+


+

-> 2

+


+


+

// vice versa Stream defined in new Environment takes next value from there 

+

// also if evaluated in other Environment

+


+

(

+

r = e.use { p.asStream };

+

r.next;

+

)

+


+


+

-> 5

+


+


+

Indeed, Streams derived from the simple Pfunc don't do much here, they just reflect values in the Environment in which they are defined. As with Functions in the first example Pfuncs can be combined with other Patterns to modify their behaviour. So a family of related Streams (common attributes) can be polled from a single pattern.

+


+


+

// try above with new pattern 

+

// here the common attributes are: period length = 2, magnitude relation of items = 1:10) 

+


+

p = Pseq([1,10], inf) * Pfunc { ~a };

+


+


+

An even more generalized operation is the use of Pcollect, which defines the following Stream behaviour: Output of the source stream will be taken as input by the collecting stream, as with Pfunc the Function defined in Pcollect will live in the Environment in which the Stream has been polled from the Pattern. The above could also be written like this:

+


+


+

p = Pcollect({ |x| x * ~a }, Pseq([1,10], inf));

+


+

p = Pseq([1,10], inf).collect({ |x| x * ~a });

+


+

p = Pseq([1,10], inf).collect(_*~a); // short form (partial application), don't overrely on it in more complicated cases

+


+


+

There is another Pattern engaging Functions, thus allowing to benefit from environment-dependance: Plazy. it evaluates a Function that returns a Pattern to be embedded in a stream. For repeated embedding the Plazy can be wrapped into a Pn. If a generated Pattern repeats infinitely, there will not be any further evaluation. So when using Plazy have a close look at the inner Pattern's repeat arg.

+


+


+

// with each evaluation of Plazy's Function a new random sequence of length = 2 will be generated and repeated 3 times

+

// maximum range of the whole sequence is controlled by the environmental variable ~a

+


+

(

+

p = Pn(Plazy { Pseq({ rand2(~a) } ! 2, 3) });

+

q = p.asStream;

+

~a = 3;

+

q.nextN(60);

+

)

+


+

// instead of using an Environment we can use an instance of its subclass Event which has handy syntax. 

+

// new empty Event:  

+


+

();

+


+

// new Event with var ~a set, range enlarged:  

+


+

(

+

e = (a: 10);

+

r = e.use { p.asStream };

+

r.nextN(60);

+

)

+


+

// compare, both streams are demanded values in same Environment, but they are attached to different ones

+


+

q.nextN(60);

+


+


+

This example was still similar to the ones before, basically a loop modified by a factor. But imagine that a Plazy could give out arbitrary new Patterns, the choice itself could depend on an environment-dependant parameter.

+


+


+

Event streams in Environments

+


+

One step closer to the sound – let's define an event pattern with single patterns that contain functional code. Again the pattern itself is neutral concerning the relation to Environments ...

+


+

(

+

p = Pbind(

+

\dur, Pfunc { ~a },

+

\midinote, Pfunc { ~b }

+

);

+

)

+


+

// ... but the stream is not neutral. It's bound to the current environment.

+


+

(

+

q = p.asStream;

+


+

~a = 0.5;

+

~b = 60;

+

)

+


+

// define a new Environment – an Event, as syntax is handy.

+


+

e = (a: 1, b: 70);

+


+

// So we have two surrounding Events as variable spaces, in which Streams of Events can live.

+

// Don't be confused by that, the stream-generated Events are a different story.

+


+

// now check a next element of the event stream in the new environment (event). 

+

// The method next must itself be passed an event -

+

// the result stems from the former current event, in which the event stream was generated

+


+

e.use { q.next(()) };

+


+

-> ( 'dur': 0.5, 'midinote': 60 )

+


+

// double check - also the second event stream belongs to its defining context

+


+

(

+

e.use { r = p.asStream; };

+

r.next(());

+

)

+


+

-> ( 'dur': 1, 'midinote': 70 )

+


+


+

EventStreamPlayers in Environments

+


+


+

Not much will change by the last transition, EventStreamPlayers are also attached to environments.

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

(

+

p = Pbind(

+

\dur, Pfunc { ~a },

+

\midinote, Pfunc { ~b }

+

);

+

)

+


+

// define two Environments (Events) with EventStreamPlayers attached to it

+


+

(

+

e = (a: 0.2, b: 60);

+

f = (a: 0.4, b: 67);

+


+

e.use { q = p.asEventStreamPlayer };

+

f.use { r = p.asEventStreamPlayer };

+

)

+


+


+

// play the players with different init data in sync

+


+

(

+

q.play(quant: 0.2);

+

r.play(quant: 0.2);

+

)

+


+


+

// now change envir variables while playing

+

// the stream will take new values at the next evaluation

+


+

f.b = 65;

+


+

e.b = 62;

+


+

(

+

q.stop;

+

r.stop;

+

)

+


+


+

The VarGui interface can be used to control running EventStreamPlayers in that way. They may be passed directly, then their attached Environments will be taken for variable setting: 

+


+


+

// start playing from gui

+


+

(

+

v = VarGui([[

+

\a, [0.2, 0.8, \lin, 0.2, 0.2],

+

\b, [48, 80, \lin, 1, 58]

+

],[

+

\a, [0.2, 0.8, \lin, 0.2, 0.4],

+

\b, [48, 80, \lin, 1, 67]

+

]],

+

stream: [q, r], quant: 0.2

+

).gui;

+

)

+


+

// so you could still set from outside

+

+

f.b = 65;

+

+

+

But also the event pattern can be passed directly (recommended). Then new separate Environments will be generated automatically, 

+

changing envir variables by accident is very unlikely.

+


+


+

(

+

v = VarGui({ [

+

\a, [0.2, 0.8, \lin, 0.2, 0.2 * (4.rand + 1) ],

+

\b, [48, 80, \lin, 1, 48.rrand(80) ]

+

] } ! 10, 

+

stream: p ! 10, quant: 0.2

+

).gui(tryColumnNum: 2);

+

)

+


+

// however, environments are accessible if necessary

+

+

v.envirs;

+


+

 

+


+


+


+


+


+ + diff --git a/Help/Event patterns and LFOs.html b/Help/Event patterns and LFOs.html new file mode 100644 index 0000000..60ccda8 --- /dev/null +++ b/Help/Event patterns and LFOs.html @@ -0,0 +1,582 @@ + + + + + + + + + + + +

Event patterns and LFOs summary of some LFO control strategies for event patterns 

+


+

Part of: miSCellaneous

+


+

See also: Working with HS and HSpar, VarGui, VarGui shortcut builds, HS with VarGui

+


+


+

Basic distinction: synths generated by an event pattern can be controlled directly by a LFO (synths wired or mapped to control buses) or on a per-event base. The latter can be achieved by language-only strategies or with help of control synths. For the sake of clarity and comparison most examples use the default instrument and pitch as control parameter. 

+


+


+

1.) Control by new values per event

+


+

Example 1a:   Functions of time

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

(

+

// LFO defined as Function

+


+

f = { |x| (x * 2).sin * 3 + (x * 0.3).sin }; 

+


+

p = Pbind( 

+

    \dev, Ptime().collect(f), // current time passed to function

+

    \midinote, Pkey(\dev) + 60 + [0, 4], 

+

    \amp, 0.05, 

+

    \dur, 0.15 

+

).play; 

+

)

+


+

p.stop;

+


+


+

////////////////////////// 

+


+

// example with GUI

+


+


+

(

+

// parametric control function

+


+

f = { |x| (x * ~a[0]).sin * ~b[0] + ((x * ~a[1]).sin * ~b[1]) }; 

+


+

p = Pbind( 

+

    \dev, Ptime().collect(f), 

+

    \midinote, Pkey(\dev) + 60 + [0, 4], 

+

    \amp, 0.05,

+

    \dur, 0.15 

+

); 

+


+

v = VarGui([

+

\a, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2,

+

\b, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2],

+

stream: p

+

).gui

+

)

+


+

// add a hook that re-plots control function after every slider change

+


+

(

+

u = Plotter(bounds: Rect(200, 200, 700, 500));

+


+

// evaluation points

+


+

x = (0, 0.1..20);

+


+

// EventStreamPlayer is run in separate Environment, 

+

// function values have to be polled from there,

+

// evaluate function initially and add it as mouseUp slider action

+


+

g = { u.value_(f.inEnvir(v.envirs.first).(x)).refresh };

+


+

g.();

+


+

v.addSliderAction(g);

+

)

+


+


+


+

////////////////////////// 

+


+

// GUI example with two LFOs

+


+


+

(

+

// parametric control function

+


+

f = { |x| (x * ~a[0]).sin * ~b[0] + ((x * ~a[1]).sin * ~b[1]) }; 

+


+

p = Pbind( 

+

    \dev, Ptime().collect(f), 

+

    \midinote, Pkey(\dev) + Pfunc { ~add }, 

+

    \amp, 0.05,

+

    \dur, 0.15 

+

); 

+


+

// add some harmonies

+


+

q = Padd(\midinote, [-12, -7, 0, 5], p);

+

r = Padd(\midinote, [0, 2.5], p);

+


+

v = VarGui([70, 55].collect { |x| [

+

\a, { [0, 5, \lin, 0.01, rrand(0.0, 5)] } ! 2,

+

\b, { [0, 5, \lin, 0.01, rrand(0.0, 5)] } ! 2,

+

\add, [x-2, x+2, \lin, 0.01, x]]

+

},

+

stream: [r,q], quant: 0.15

+

).gui

+

)

+


+

// add a hook that re-plots control function after every slider change

+


+

(

+

u = Plotter(bounds: Rect(200, 200, 700, 500));

+


+

// evaluation points

+


+

x = (0, 0.1..20);

+


+

// EventStreamPlayer is run in separate Environment, 

+

// function values have to be polled from there,

+

// evaluate function initially and add it as mouseUp slider action

+


+

g = { u.value_(v.envirs.collect { |e| f.inEnvir(e).(x) }).refresh };

+


+


+

g.();

+


+

v.addSliderAction(g);

+

)

+


+


+


+

Example 1b:   Envelopes

+


+


+

(

+

e = Env([0, 10, 0], [2,1], \sin);

+

e.plot;

+

)

+


+

// currently (SC 3.4.4) this will play the envelope once 

+

// and then continue with the end value

+


+

(

+

p = Pbind( 

+

    \dev, e, 

+

    \midinote, Pkey(\dev) + 60 + [0, 4], 

+

    \amp, 0.05, 

+

    \dur, 0.15 

+

).play; 

+

)

+


+

p.stop;

+


+


+

// you can use modulo calculus for looping

+


+

(

+

p = Pbind( 

+

    \dev, Ptime().collect { |t| e[t % (e.times.sum)] }, 

+

    \midinote, Pkey(\dev) + 60 + [0, 4], 

+

    \amp, 0.05, 

+

    \dur, 0.15 

+

).play; 

+

)

+


+

p.stop;

+


+


+

////////////////////////// 

+


+

// example with GUI

+


+

(

+

n = 5;

+


+

p = Pbind( 

+

    \dev, Ptime().collect { |t| e[t % (e.times.sum)] }, 

+

    \midinote, Pkey(\dev) + 60 + [0, 4], 

+

    \amp, 0.05, 

+

    \dur, 0.15 

+

);

+


+

v = VarGui([

+

\levels, { [-15, 15, \lin, 0.01, rrand(-15.0, 15)] } ! n,

+

\times, { [0.5, 3, \lin, 0.01, rrand(0.5, 3)] } ! (n-1),

+

\curves, { [0, 7, \lin, 1, rrand(0, 7)] } ! (n-1),

+

\stretch, [0.1, 10, \lin, 0.01, 1]],

+

stream: p

+

).gui;

+

)

+


+

// add a hook that plots envelope after every slider change

+


+

(

+

u = Plotter(bounds: Rect(200, 200, 700, 500));

+


+

g = { 

+

v.envirs.first.use { e = Env(~levels, ~times * ~stretch, ~curves) };

+

u.value_(e.asSignal).refresh; 

+

};

+


+

g.();

+


+

v.addSliderAction(g);

+

)

+


+


+


+


+

Example 1c:   SharedOut / shared memory

+


+


+

SharedOut will be deprecated in future releases of SC and replaced by a shared memory mechanism (Tim Blechmann). 

+

SharedOut is at least included in version 3.4.4.

+


+


+

// internal server needed for all examples with SharedOut,

+

// shared memory also works with local server

+


+

(

+

s = Server.internal;

+

Server.default = s;

+

s.boot;

+

)

+


+

// start LFO

+


+

x = { SharedOut.kr(0, LFDNoise3.kr(0.3, 20, 70)) }.play;

+


+


+

// play event pattern

+


+

(

+

p = Pbind(

+

\dur, 0.15, 

+

\midinote, Pfunc { s.getSharedControl(0) }

+

).play;

+

)

+

+

(

+

p.stop;

+

x.free;

+

)

+


+

////////////////////////// 

+


+

// example with GUI

+


+

// ATTENTION: this version of the example works with SC versions > 3.4.4

+

// in which SharedOut is still supported and which already include 

+

// the fix of a minor bug which blocked adding of SynthDefs.

+

// See below for an equivalent example with shared memory.

+


+

// If you're using a version <= 3.4.4 you can fix it by yourself, 

+

// adding this method to SharedOut and recompile:

+

// *numFixedArgs { ^1 }

+


+

// ... or take the example version below the following version

+


+

(

+

s = Server.internal;

+

Server.default = s;

+

s.boot;

+

)

+


+

(

+

SynthDef(\control, { |midiCenter, dev, devFreq| SharedOut.kr(0, LFDNoise3.kr(devFreq, dev, midiCenter)) }).add;

+


+

p = Pbind(

+

\dur, 0.15, 

+

\midinote, Pfunc { s.getSharedControl(0) } + [0, 4]

+

);

+


+

// start control synth before stream

+

+

v = VarGui(synthCtr: [

+

\midiCenter, [50, 80, \lin, 0.01, 70],

+

\dev, [0, 20, \lin, 0.01, 20],

+

\devFreq, [0, 3, \lin, 0.01, 0.5]],

+

synth: \control, stream: p

+

).gui(playerPriority: \synth);

+

)

+


+


+

// this version of the example works also with SC versions <= 3.4.4

+

  

+

(

+

SynthDef(\control, { |midiCenter, dev, devFreq| SharedOut.kr(0, LFDNoise3.kr(devFreq, dev, midiCenter)) }).send(s);

+

)

+


+

(

+

x = Synth(\control).register;  

+


+

// or start paused:

+

// x = Synth.newPaused(\control).register; 

+


+

p = Pbind(

+

\dur, 0.15, 

+

\midinote, Pfunc { s.getSharedControl(0) } + [0, 4]

+

);

+

)

+


+

(

+

v = VarGui(synthCtr: [

+

\midiCenter, [50, 80, \lin, 0.01, 70],

+

\dev, [0, 20, \lin, 0.01, 20],

+

\devFreq, [0, 3, \lin, 0.01, 0.5]],

+

synth: x, stream: p

+

).gui(playerPriority: \synth);

+

)

+


+


+


+

// shared memory example, SC version >= 3.5

+

// start LFO

+


+

c = Bus.control(s, 1);

+


+

x = { Out.kr(c, LFDNoise3.kr(0.3, 20, 70)) }.play;

+


+


+

// play event pattern

+


+

(

+

p = Pbind(

+

\dur, 0.15, 

+

\midinote, Pfunc { c.getSynchronous }

+

).play;

+

)

+

       

+

(

+

p.stop;

+

x.free;

+

)

+


+

Example 1d:   HS / PHS and related

+


+

With HS server values can be used in PHS objects which mimic event patterns. This is achieved by an OSC demand and respond mechanism which introduces a small amount of additional latency. It works with local and internal server, see Working with HS and HSpar for further details. Using the HS family with VarGui is discussed in HS with VarGui. 

+

The HS / PHS approach would especially be of interest if control behaviour could more easily be defined by server means than in SC lang (e.g. specific and / or nested UGens) but data should also be further manipulated in the language (e.g. for some kind of combinatorial use such as harmonic or polyphonic calculations).

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// a HS contains the control synth definition but will also hold playing Synth instances

+


+

h = HS(s, { |midiCenter = 70, dev = 20, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) });

+


+


+

// a PHS refers to a HS and, when played, takes control over the control synth

+


+

p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) + [0, 4] ]).play;

+


+


+

// stop player and control synth 

+


+

p.free; 

+


+


+

Methods of linked playing / stopping and resuming (stream + help synth) are supported as well as reference to an already playing HS by PHSuse. Various kinds of control synth control and synth value reference are possible with two or more help synths (see HSpar, PHSpar and PHSparUse). 

+


+


+

Example 1e:   audio synths reading from a control bus, discretized

+


+

Derived from (2a), disadvantage: SynthDef must be adapted to control needs beforehand.

+


+

(

+

c = Bus.control(s,1);

+

d = Bus.control(s,1);

+


+

SynthDef(\perc_1e, {|amp = 0.1, bus, att = 0.01, rel = 1|

+

var in = In.kr(bus, 1);

+

Out.ar(0, (SinOsc.ar(Latch.kr(in, in).midicps, 0, amp) * 

+

EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2)

+

}).add;

+

)

+


+

(

+

x = { Out.kr(c, LFDNoise3.kr(1, 5, 75)) }.play;

+

y = { Out.kr(d, LFDNoise3.kr(1, 5, 65)) }.play;

+


+

p = Pbind(

+

\instrument, \perc_1e,

+

\dur, 0.3,

+

\amp, 0.07,

+

\bus, [c, d]

+

).play;

+

)

+


+

(

+

p.stop;

+

x.free;

+

y.free;

+

)

+


+


+

Example 1f:   Pseg

+


+

Pseg can work like a kind of meta pattern for LFO-like control, patterns are used to pass envelope data.

+


+

(

+

p = Pbind(

+

    \note, Pseg(Pseq([0, Pwhite(3, 10, 1)], inf), Pseq([1, 3],inf), 'lin'),

+

    \dur, 0.2

+

).play;

+

)

+


+

p.stop;

+


+


+

2.) Continuous LFO control

+


+


+

Example 2a:   audio synths reading from a control bus

+


+

The disadvantage of this strategy (compared to 2b) is that synth definitions have to be written especially for control purposes. It must be known in advance which parameters should be controlled by another synth.

+


+

(

+

c = Bus.control(s,1);

+


+

SynthDef(\perc_2a, {|amp = 0.1, bus = 0, att = 0.01, rel = 0.25|

+

Out.ar(0, (SinOsc.ar(In.kr(bus, 1).midicps, 0, amp) * 

+

EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2)

+

}).add;

+

)

+


+

(

+

x = { Out.kr(c, LFDNoise3.kr(3, 10, 65)) }.play;

+


+

p = Pbind(

+

\instrument, \perc_2a,

+

\dur, 0.3,

+

\bus, c

+

).play;

+

)

+


+

(

+

p.stop;

+

x.free;

+

)

+


+


+


+

Example 2b:   audio synths mapped to a control bus

+


+

In general more practical than (2a), though by SC vs 3.4.4 reserved keys (e.g. \freq) can't be mapped to a bus, under these circumstances args would have to be renamed.

+


+

(

+

c = Bus.control(s,1);

+

d = Bus.control(s,1);

+


+

SynthDef(\perc_2b, {|amp = 0.1, midi = 60, att = 0.01, rel = 0.25|

+

Out.ar(0, (SinOsc.ar(midi.midicps, 0, amp) * 

+

EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2)

+

}).add;

+

)

+


+

(

+

x = { Out.kr(c, LFDNoise3.kr(1, 5, 75)) }.play;

+

y = { Out.kr(d, LFDNoise3.kr(1, 5, 65)) }.play;

+


+

p = Pbind(

+

\instrument, \perc_2b,

+

\dur, 0.3,

+

\midi, [c, d].collect(_.asMap)

+

).play;

+

)

+


+

(

+

p.stop;

+

x.free;

+

y.free;

+

)

+


+


+

////////////////////////// 

+


+

// example with GUI

+


+


+

(

+

c = Bus.control(s,1);

+

d = Bus.control(s,1);

+


+

SynthDef(\perc_2b, {|amp = 0.1, midi = 60, att = 0.01, rel = 0.25|

+

Out.ar(0, (SinOsc.ar(midi.midicps, 0, amp) * 

+

EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2)

+

}).add;

+


+

SynthDef(\control_2b, { |midiCenter = 70, dev = 20, devFreq = 1, out = 0| 

+

Out.kr(out, LFDNoise3.kr(devFreq, dev, midiCenter)) 

+

}).add;

+

)

+


+

(

+

p = Pbind(

+

\instrument, \perc_2b,

+

\dur, Pfunc { ~dur },

+

// following values will be collections of two elements

+

\amp, Pfunc { ~amp },

+

\att, Pfunc { ~att },

+

\rel, Pfunc { ~rel },

+

\midi, [c, d].collect(_.asMap)

+

);

+


+

// in gui start control synths before stream player !

+


+

v = VarGui([

+

\dur, [0.05, 0.5, \lin, 0.005, 0.2],

+

// setting envir variables to collections of two elements

+

\amp, [0, 0.1, \lin, 0.005, 0.07] ! 2,

+

\att, [0.005, 0.1, \lin, 0.005, 0.01] ! 2,

+

\rel, [0.005, 0.5, \lin, 0.005, 0.1] ! 2

+

],

+

2.collect { |i| 

+

var bus = [c,d][i].index;

+

[\midiCenter, [60, 80, \lin, 0.01, [65, 75][i] ],

+

\dev, [0, 10, \lin, 0.01, 10],

+

\devFreq, [0, 3, \lin, 0.01, 0.5],

+

\out, [bus, bus, \lin, 1, bus]] 

+

}, p, \control_2b ! 2 

+

).gui(sliderPriority: \synth, playerPriority: \synth);

+

)

+


+


+


+ + diff --git a/Help/Event patterns and array args.html b/Help/Event patterns and array args.html new file mode 100644 index 0000000..b703a00 --- /dev/null +++ b/Help/Event patterns and array args.html @@ -0,0 +1,680 @@ + + + + + + + + + + + +

Event patterns and array args setting and passing arrays and envelopes via patterns

+


+

Part of: miSCellaneous

+


+


+

This tutorial covers some use cases of array args, especially passing arrays to synths with patterns.

+


+


+

Examples

+


+

1.) Alternative writing of arrayed args in SynthDefs

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// SynthDef with array of overtone weights,

+

// weights can additionally be influenced with a dampExp arg unequal to 0, 

+

// see examples below.

+


+

(

+

// The standard way to define array args: 

+

// when appearing within the list of args, a literal Array must be used,

+

// shortcut (1..8) generates an Array with Integers from 1 to 8

+


+

SynthDef(\array_1a, { |out = 0, freq = 440, otAmps = #[1,1,1,1,1,1,1,1], dampExp = 0,

+

att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02|

+

var sig, env, freqs, amps;

+

freqs = (freq * (1..8)).clip(20, 20000).lag(freqLag);

+

amps = ((otAmps / ((1..8) ** dampExp)).normalizeSum * amp).lag(otLag);

+

sig = SinOsc.ar(freqs, 0, amps);

+

env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2);

+

Out.ar(out, Splay.ar(sig) * env)

+

}).add

+

)

+


+

// Note that SynthDef \array_1a uses the array arg's size (8) at two further places (arrays (1..8)).

+

// As a literal Array, by its nature, requires the explicit writing of its items,

+

// this becomes arkward with larger arrays and/or rewriting the SynthDef with other sizes.

+

// For those reasons the use of NamedControl turns out to be very convenient with array args,

+

// it also gives an easy way of lagging.

+


+


+

(

+

// Alternative to SynthDef \array_1a using NamedControl:

+

// Although a NamedControl can be written at any position within the SynthDef,

+

// it's a useful convention to invent it directly after the args list

+

// by assigning it to a variable of the same name (so code with literal Array args can be reused easily).

+

// With NamedControl the array size can now also be written as a variable,

+

// which allows to define SynthDefs with different array sizes on the fly.

+

// Also note NamedControl's shortcuts aSymbol.kr / aSymbol.kr

+

// which make its use even more comfortable.

+


+

// define size for SynthDef

+

n = 8;

+


+

// define SynthDef

+

// shortcut 1!n (short for 1.dup(n)) generates an Array of size n filled with 1.

+


+

SynthDef(\array_1b, { |out = 0, freq = 440, dampExp = 0,

+

att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02|

+

var otAmps = NamedControl.kr(\otAmps, 1!n); // shortcut: otAmps = \otAmps.kr(1!n);

+

var sig, env, freqs, amps;

+

freqs = (freq * (1..n)).clip(20, 20000).lag(freqLag);

+

amps = ((otAmps / ((1..n) ** dampExp)).normalizeSum * amp).lag(otLag);

+

sig = SinOsc.ar(freqs, 0, amps);

+

env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2);

+

Out.ar(out, Splay.ar(sig) * env)

+

}).add

+

)

+


+


+

// As array sizes of SynthDefs are fixed you might want to define for a number

+

// of Integers and name the SynthDefs appropriately.

+

// Here's such a "SynthDef factory":

+

// we get SynthDefs of names \array_1b_1, ..., \array_1b_16 with corresponding array sizes,

+

// see Ex. 3b for a use case.

+


+

(

+

(1..16).do { |n|

+

var name = \array_1b ++ \_ ++ n;

+

SynthDef(name, { |out = 0, freq = 440, dampExp = 0,

+

att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02|

+

var otAmps = NamedControl.kr(\otAmps, 1!n); // shortcut: otAmps = \otAmps.kr(1!n);

+

var sig, env, freqs, amps;

+

freqs = (freq * (1..n)).clip(20, 20000).lag(freqLag);

+

amps = ((otAmps / ((1..n) ** dampExp)).normalizeSum * amp).lag(otLag);

+

sig = SinOsc.ar(freqs, 0, amps);

+

env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2);

+

Out.ar(out, Splay.ar(sig) * env)

+

}).add

+

}

+

)

+


+


+


+

2.) Setting array args and array fields of a running synth

+


+


+

Ex. 2a: Setting array args of a running synth

+


+


+

// start Synth, SynthDefs \array_1a, \array_1b and \array_1b_8 are equivalent

+


+

x = Synth(\array_1a, [freq: 300, amp: 0.2])

+


+


+

// only odd partials (clarinet-like)

+


+

x.set(\otAmps, [1, 0, 1, 0, 1, 0, 1, 0])

+


+


+

// emphasize one partial

+


+

x.set(\otAmps, [1, 0, 1, 0, 1, 5, 1, 0])

+


+


+

// only lower ones

+


+

x.set(\otAmps, [1, 1, 1, 1, 0, 0, 0, 0])

+


+


+

// default again

+


+

x.set(\otAmps, [1, 1, 1, 1, 1, 1, 1, 1])

+


+


+


+

// force lower partials with dampExp > 0

+


+

x.set(\dampExp, 1.5)

+


+


+

// force higher partials with dampExp < 0

+


+

x.set(\dampExp, -1.5)

+


+


+

// default again

+


+

x.set(\dampExp, 0)

+


+


+

// release

+


+

x.release

+


+


+

Ex. 2b: Setting array args of a running synth with Pbind of event type \set

+


+


+

// For many use cases Pmono (see 2c) is the most practical solution

+

// as it doesn't require explicit starting of a synth.

+

// However sometimes it is necessary to access the running synth itself,

+

// then a Pbind with event type \set is a good choice.

+


+


+

// start Synth silently

+


+

x = Synth(\array_1a, [freq: 200, amp: 0])

+


+


+

// Pbind of event type set:

+

// args to be set must be listed.

+

// Note that the array arg requires double brackets (syntactic distinction from setting multiple nodes)

+


+

(

+

p = Pbind(

+

\dur, 0.2,

+

\type, \set,

+

\id, x,

+

\args, #[freq, amp, dampExp, otAmps], // must be given explicitely

+

\midinote, Pwhite(45.0, 70), // for midinote freq must be set

+

\amp, 0.3,

+

\dampExp, Pwhite(0, 3),

+

\otAmps, [[2, 1, 3, 2, 1, 2, 2, 1]] // double brackets for array arg !

+

).play

+

)

+


+

(

+

// stop EventStreamPlayer and release Synth

+


+

p.stop;

+

x.release;

+

)

+


+


+


+


+

// start Synth silently

+


+

x = Synth(\array_1a, [freq: 200, amp: 0]);

+


+


+

// Sequencing the array arg:

+

// rising spectral shape, falling fundamental

+


+

(

+

// Array for Pseq, we need an array of doubly bracketed arrays or

+

// ref'd arrays as in Ex. 2c.

+


+

o = [

+

[[1, 1, 0, 0, 0, 0, 0, 0]],

+

[[1, 0, 1, 0, 0, 0, 0, 0]],

+

[[1, 1, 0, 1, 0, 0, 0, 0]],

+

[[1, 0, 1, 0, 1, 0, 0, 0]],

+

[[1, 1, 0, 1, 0, 1, 0, 0]],

+

[[1, 0, 1, 0, 1, 0, 1, 0]],

+

[[1, 0, 0, 1, 0, 1, 0, 1]]

+

];

+


+

p = Pbind(

+

\dur, 0.2,

+

\type, \set,

+

\id, x,

+

\args, #[freq, amp, otAmps], // must be given explicitely

+

\midinote, Pn(Plazy { Pseq((70..50)) / rrand(1, 1.2) }), 

+

\amp, 0.3,

+

\otAmps, Pseq(o, 30) 

+

).play

+

)

+


+

(

+

// stop EventStreamPlayer and release Synth

+


+

p.stop;

+

x.release;

+

)

+


+


+

Ex. 2c: Setting array args of a running synth with Pmono

+


+


+

// Rewriting second example of 2b, shorter with Pmono.

+

// Instead of doubly bracketed arrays you can choose Refs of Arrays also.

+

// Note that this alternative is not valid for a single nested Array as 

+

// in the first example of 2b.

+


+

(

+

o = [

+

`[1, 1, 0, 0, 0, 0, 0, 0],

+

`[1, 0, 1, 0, 0, 0, 0, 0],

+

`[1, 1, 0, 1, 0, 0, 0, 0],

+

`[1, 0, 1, 0, 1, 0, 0, 0],

+

`[1, 1, 0, 1, 0, 1, 0, 0],

+

`[1, 0, 1, 0, 1, 0, 1, 0],

+

`[1, 0, 0, 1, 0, 1, 0, 1]

+

];

+


+

p = Pmono(\array_1a,

+

\dur, 0.2,

+

\midinote, Pn(Plazy { Pseq((70..50)) / rrand(1, 1.2) }), 

+

\amp, 0.3,

+

\otAmps, Pseq(o, 30) 

+

).play

+

)

+


+


+

// stop EventStreamPlayer from Pmono (synth is released also)

+


+

p.stop;

+


+


+


+

Ex. 2d: Setting i-th fields of a running synth

+


+


+

// start Synth

+


+

x = Synth(\array_1a, [freq: 200, amp: 0.3])

+


+


+

// by default otAmps equals [1, 1, 1, 1, 1, 1, 1, 1]

+


+

// Since SC 3.6.x there exists method seti for setting single elements of arrays:

+

// turn off high overtones

+


+

x.seti(\otAmps, 7, 0)

+


+

x.seti(\otAmps, 6, 0)

+


+

x.seti(\otAmps, 5, 0)

+


+


+

x.release;

+


+


+

// With older SC versions you can use the following helper functions to achieve the same.

+

// This requires that the SynthDef has been added in order to have control arg info in SynthDescLib.

+


+

(

+

~getCtlIndex = { |defName, argName, index| 

+

    var x = SynthDescLib.global.at(defName.asSymbol).controls 

+

        .collect({|x| x.name.asSymbol }).indexOf(argName.asSymbol); 

+

    x !? { x + index }; 

+

}; 

+


+

~setiID = { |server, defname, nodeID, key, index, value| 

+

    server.sendMsg(15, nodeID, ~getCtlIndex.(defname, key, index), value); 

+

}; 

+


+


+

~seti = { |node, key, index, value| 

+

    ~setiID.(node.server, node.defName, node.nodeID, key, index, value); 

+

}; 

+

)

+


+


+

// start Synth

+


+

x = Synth(\array_1a, [freq: 200, amp: 0.5])

+


+


+

// turn off high overtones

+


+

~seti.(x, \otAmps, 7, 0)

+


+

~seti.(x, \otAmps, 6, 0)

+


+

~seti.(x, \otAmps, 5, 0)

+


+

x.release;

+


+


+


+

Ex. 2e: Setting i-th fields of a running synth with patterns

+


+


+

// For SC versions before invention of method seti use helper functions from Ex. 2d in Pbind.

+


+

// start Synth

+


+

x = Synth(\array_1a, [freq: 200, amp: 0.3])

+


+


+

// sequence setting of single fields

+

// As this is currently not integrated with Pmono or event type \set

+

// it must be done explicitely. Method 'makeBundle' with server latency arg

+

// ensures that array field setting is done in parallel to

+

// other settings triggered by the event.

+


+

(

+

// continously subtract and add 7 overtones

+


+

p = Pbind(

+

\type, \rest,

+

\dur, 0.2,

+

\otAmp, Pstutter(7, Pseq([0,1], inf)),

+

\amp, 0.3,

+

\i, Pn(Pshuf((1..7))),

+

// use Function ~seti (2d) for SC versions without method seti:

+

\do, Pfunc { |e| s.makeBundle(s.latency, { ~seti.(x, \otAmps, e.i, e.otAmp) }) }

+

// for newer SC versions with method seti you can use this line instead:

+

// \do, Pfunc { |e| s.makeBundle(s.latency, { x.seti(\otAmps, e.i, e.otAmp) }) } 

+

   ).trace.play

+

)

+


+

// stop player and synth

+


+

(

+

p.stop;

+

x.release;

+

)

+


+


+

// This approach can be extended by setting more than one field per event.

+

// In some cases this might be a reasonable alternative to setting whole arrays

+

// of running synths (2b, 2c), which requires more OSC traffic.

+


+

// start Synth from Ex. 1 with 16 overtones

+


+

x = Synth(\array_1b_16, [freq: 100, amp: 0.3])

+


+

(

+

// lists for bookkeeping of substracted and added overtones

+

a = (1..16).asList;

+

b = List[];

+


+

// Function to shovel indices from list to list

+


+

f = { |list1, list2|

+

var x = list1.choose;

+

list1.remove(x);

+

list2.add(x);

+

x

+

};

+


+

// continously subtract and add 5 x 3 overtones

+


+

p = Pbind(

+

\type, \rest,

+

\dur, 0.2,

+

\otAmp, Pstutter(5, Pseq([0,1], inf)),

+

\amp, 0.3,

+

// shoveling indices from a to b and back, outputting sorted index tripels

+

\i, Pseq([

+

Pfinval(5, Pclump(3, Pfunc { f.(a, b) } )),

+

Pfinval(5, Pclump(3, Pfunc { f.(b, a) } ))

+

], inf).collect(_.sort),

+

// use Function ~seti (2d) for SC versions without method seti:

+

\do, Pfunc { |e| s.makeBundle(s.latency, { e.i.do { |j| ~seti.(x, \otAmps, j, e.otAmp) } }) }   

+

// for newer SC versions with method seti you can use this line instead:

+

// \do, Pfunc { |e| s.makeBundle(s.latency, { e.i.do { |j| x.seti(\otAmps, j, e.otAmp) } }) } 

+

).trace.play

+

)

+


+

// stop player and synth

+


+

(

+

p.stop;

+

x.release;

+

)

+


+


+


+

Ex. 2f: Alternatives with demand ugens

+


+

// Besides from passing arrays, array sequencing can be 

+

// done within synths by demand ugens.

+

// This is saving OSC bandwidth, especially with large arrays and short durations,

+

// for more complicated sequencing tasks coding might be harder than with patterns.

+


+

(

+

// array sequencing within SynthDef

+


+

q = [

+

[1, 1, 0, 0, 0, 0, 0, 0],

+

[1, 0, 1, 0, 0, 0, 0, 0],

+

[1, 1, 0, 1, 0, 0, 0, 0],

+

[1, 0, 1, 0, 1, 0, 0, 0],

+

[1, 1, 0, 1, 0, 1, 0, 0],

+

[1, 0, 1, 0, 1, 0, 1, 0],

+

[1, 0, 0, 1, 0, 1, 0, 1]

+

];

+


+

// duration will have to be passed with a key unequal to reserved keyword \dur

+


+

SynthDef(\array_1c, { |out = 0, freq = 440, dampExp = 0, duration = 0.2,

+

att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02|

+

var otAmps, sig, env, freqs, amps, arr;

+

otAmps = Demand.kr(Impulse.kr(1 / duration), 0, Dseq(q, inf));

+

freqs = (freq * (1..8)).clip(20, 20000).lag(freqLag);

+

amps = ((otAmps / ((1..8) ** dampExp)).normalizeSum * amp).lag(otLag);

+

sig = SinOsc.ar(freqs, 0, amps);

+

env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2);

+

Out.ar(out, Splay.ar(sig) * env)

+

}).add;

+


+

// SynthDef for complete server-side sequencing 

+

// takes midiseq as array arg

+


+

SynthDef(\array_1d, { |out = 0, dampExp = 0, duration = 0.2, divLo = 1, divHi = 1.2,

+

att = 0.01, rel = 0.6, amp = 0.3, gate = 1, freqLag = 0.02, otLag = 0.02|

+

var midiseq = \midiseq.kr((70..50));

+

var trig, otAmps, sig, env, freq, freqs, amps, arr;

+

trig = Impulse.kr(1 / duration);

+

otAmps = Demand.kr(trig, 0, Dseq(q, inf));

+

freq = Demand.kr(trig, 0, Dseq(midiseq, inf) / 

+

Dstutter(midiseq.size, Dwhite(divLo, divHi))).midicps;

+

freqs = (freq * (1..8)).clip(20, 20000).lag(freqLag);

+

amps = ((otAmps / ((1..8) ** dampExp)).normalizeSum * amp).lag(otLag);

+

sig = SinOsc.ar(freqs, 0, amps);

+

env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2);

+

Out.ar(out, Splay.ar(sig) * env)

+

}).add

+

)

+


+

(

+

// equivalent to Ex 2c

+

// still using a pattern for non-array sequencing

+


+

p = Pmono(\array_1c,

+

\dur, 0.2,

+

\duration, Pkey(\dur),

+

\midinote, Pn(Plazy { Pseq((70..50)) / rrand(1, 1.2) }), 

+

\amp, 0.3

+

).play

+

)

+


+

p.stop;

+


+


+

// equivalent, now all done by synth

+


+

x = Synth(\array_1d)

+


+


+

// set midi sequence 

+


+

x.set(\midiseq, (50..70))

+


+

x.set(\midiseq, (70..50))

+


+

x.set(\midiseq, (70..50).scramble)

+


+

x.release

+


+


+


+

3.) Sequencing synths with array args by Pbind

+


+


+

Ex. 3a: Sequencing synths of same definition with array args by Pbind

+


+


+

// Using a Pbind with array args is straightforward,

+

// it's just important to remember that arrays must be in 

+

// double brackets (or wrapped into Refs). 

+

// Written explicitely it looks a bit odd as you end up with 

+

// three brackets at begin and end:

+

// Pseq([[[1, 1, 0, 0, 0, 0, 0, 0]], ... , [[1, 0, 0, 1, 0, 1, 0, 1]]], 100)

+


+


+

(

+

// Array o from definitions in Ex. 2b / 2c.

+


+

o = [

+

[[1, 1, 0, 0, 0, 0, 0, 0]],

+

[[1, 0, 1, 0, 0, 0, 0, 0]],

+

[[1, 1, 0, 1, 0, 0, 0, 0]],

+

[[1, 0, 1, 0, 1, 0, 0, 0]],

+

[[1, 1, 0, 1, 0, 1, 0, 0]],

+

[[1, 0, 1, 0, 1, 0, 1, 0]],

+

[[1, 0, 0, 1, 0, 1, 0, 1]]

+

];

+


+

// generating multiple nodes per event is also no problem,

+

// arrays from o are sent to both nodes here:

+


+

p = Pbind(

+

\instrument, \array_1a, 

+

\dur, 0.2,

+

\amp, 0.3,

+

\stepsPerOctave, 5,

+

\octave, 4,

+

\note, Pstutter(7, Pn(Pshuf((0..4)))) + [0, -4], 

+

\otAmps, Pseq(o, 100)

+

).trace.play

+

)

+


+

p.stop;

+


+


+

Ex. 3b: Sequencing synths with different array arg sizes by Pbind

+


+


+

// By using the Array o in the last examples we did a kind of zeropadding:

+

// setting unused elements to zero.

+

// When altering one running synth (as with event type \set or Pmono)

+

// one can only save OSC messages if less than all fields are changed, see Ex. 2e.

+


+

// When continuously generating new synths – as with 'normal' Pbind of type \note –

+

// there is another alternative: using SynthDefs of dedicated array arg sizes per event.

+

// This is the use case of a "SynthDef factory" as described in Ex. 1

+


+


+

(

+

// needs SynthDefs from "factory" in Ex. 1

+


+

q = [

+

[[1, 1, 1]],

+

[[1, 1, 1, 1, 1]],

+

[[1, 0, 1, 0, 1, 0, 1, 0, 1]],

+

[[1, 1, 0, 1, 0, 1, 0, 1, 0, 1]]

+

];

+


+

p = Pbind(

+

\otAmps, Pn(Pshuf(q), 100),

+

\size, Pkey(\otAmps).collect { |x| x[0].size.asSymbol },

+

\instrument, Pkey(\size).collect { |x| \array_1b_ ++ x }, // SynthDef depends on chosen otAmp array

+

\dur, 0.2,

+

\amp, 0.3,

+

\stepsPerOctave, 7,

+

\octave, 4,

+

\note, Pstutter(3, Pn(Pshuf((0..4)))) + Pn(Pshuf([[0, 2], [0, 4, 8], [0, -3, -5, -8]])) 

+

).trace.play

+

)

+


+

p.stop;

+


+


+


+

Ex. 4: Sequencing synths with envelope array args by Pbind 

+


+


+

// Env objects have a representation in a special Array format –

+

// which you can get with anEnv.asArray – the task of passing Env data to synths can thus be

+

// reduced to the task of passing Arrays in this special format.

+

// Nevertheless direct passing of Envs is possible also.

+


+

(

+

// NamedControl is recommended in that case as a literal Array of special format would be impractical.

+

// Define a SynthDef with maximum envelope size you expect to pass

+


+

SynthDef(\envArray_1, { |out = 0, freq = 440, amp = 0.1, timeScale = 1, gate = 1|

+

var sig, env, envArray, envSig;

+

envArray = Env([0, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0]).asArray; // works also without '.asArray'

+

env = \env.kr(envArray);  // shortcut for NamedControl.kr(\env, envArray)

+

envSig = EnvGen.kr(env, gate, timeScale: timeScale, doneAction: 2); 

+

sig = Saw.ar([freq, freq * 2.01], amp); 

+

Out.ar(out, sig * envSig)

+

}).add

+

)

+


+

// Pbind uses event type \on to avoid setting gate to 0 and receiving messages "node not found",

+

// synths are ended by envelopes anyway.

+


+


+

( 

+

p = Pbind( 

+

\type, Pshuf([\on, \on, \rest], inf),

+

\instrument, \envArray_1, 

+

\dur, Pn(Pshuf([1, 1/2, 1/2]), 30), 

+

\midinote, Pn(Pshuf((40..80))) + Pn(Pshuf([[0.5, 11.5], [0, 4], [0, -7], [-0.5, -9.5]])),

+

+

// envData contains env types, determined by levels and times.

+

// Times are only relations, within the synthdef they are scaled by the timeScale arg.

+

\envData, Pn(Pshuf([ 

+

[[0, 1, 0], [1, 1]], 

+

[[0, 1, 1/4, 1, 0], [1, 1, 1, 1]], 

+

[[0, 1, 1/4, 1, 1/4, 1, 0], [1, 1, 1, 1, 1, 1]]

+

])),

+

+

// *x splits the envData array into levels and times, Env is converted in to an Array automatically

+

\env, Pkey(\envData).collect { |x| Env(*x) }, 

+

+

// when wanting to pass the Array explicitely it would require

+

// wrapping into an additional Array which is necessary for passing:

+

// \env, Pkey(\envData).collect { |x| [Env(*x).asArray] }, 

+

+

\timeScale, Pfunc { |e| e.dur / e.envData[1].sum } 

+

).trace.play; 

+

) 

+


+

p.stop;

+


+


+


+ + diff --git a/Help/EventShortcuts.html b/Help/EventShortcuts.html new file mode 100644 index 0000000..b9d982a --- /dev/null +++ b/Help/EventShortcuts.html @@ -0,0 +1,322 @@ + + + + + + + + + + + +

EventShortcuts holds default and user-defined dictionaries of shortcuts for events and event patterns 

+


+

Part of: miSCellaneous

+


+

Inherits from: Object

+


+

Container for dictionaries of shortcuts for the event framework, which can be defined by the user. Shortcuts might be for event keywords or any other (e.g. synth args). At every time one shortcut dictionary is current, but it's only active if EventShortcuts is turned on. Dictionaries are encapsulated and can only be accessed via copies and posting to prevent unintended changes. For event keywords see James Harkins' Practical Guide to Patterns (especially chapters PG_07_Value_Conversions and PG_08_Event_Types_and_Parameters).

+


+


+

See also: Other event and pattern shortcuts, PLx and live coding with Strings

+


+


+

Some Important Issues

+


+

Implementation of shortcuts works like this: if you don't turn EventShortcuts on at all, nothing is changed in the event framework – if you turn it on a mapping function is prepended to every event type function, if this has not been done before in this session and the event type function hasn't been newly defined since last prepending – if you turn it off the prepended function is still there, but does no mapping. 

+

Therfore shortcuts won't work automatically after new definitions of event types. You'd have to turn EventShortcuts on again or apply the method prefixEventTypes. Quite obviously, switching between different shortcut dictionaries might cause a mess while playing (or pausing and resuming) patterns with these shortcuts. But these are exceptional cases, a typical usage would be defining your personal shortcut dictionary (e.g. in the startup file), turning EventShortcuts on and playing therewith, then maybe turning it off and on again on occasion. 

+


+

NOTE: Some pattern classes (e.g. Ppar) don't work correctly with EventShortcuts, but this can be circumvented by applying shortcuts to source event patterns before, see method Pattern::eventShortcuts.

+


+


+

Class Methods

+


+

*add (name, dict, overwrite)

+

+

Adds a new named IdentityDictionary of shortcuts.

+

+

name - Symbol or String.

+

dict - IdentityDictionary of abbreviations (keys given as Symbols) and original names (values given as Symbols).

+

overwrite - Boolean. Determines if a shortcut dictionary of that name – if existing at all – is overwritten. Defaults to false.

+


+


+

*addOnBase (baseName, newName, dict, overwrite)

+

+

Adds a new named IdentityDictionary of shortcuts based on the copy of an existing one.

+

+

baseName - Symbol or String. Name of the shortcut dictionary to build upon.

+

newName - Symbol or String. Name of the new shortcut set.

+

dict - IdentityDictionary of new or/and additional abbreviations (keys given as Symbols) 

+

and original names (values given as Symbols).

+

overwrite - Boolean. Determines if a shortcut dictionary of that name – if existing at all – is overwritten. Defaults to false.

+

Attention: overwrite only determines overwriting of an old dictionary of the same name. It doesn't influence

+

the overwriting in the copy of the base dictionary itself, as exactly this is a main aim of the method

+

(you might want to replace the association 's'-> 'strum' by 's' -> 'server').

+


+


+

*remove (name)

+

+

Removes a named IdentityDictionary of that name.

+

+

name - Symbol or String.

+


+


+

*removeAll

+

+

Removes all IdentityDictionaries except \default.

+

+


+

*copyDict (name)

+

+

Returns a copy of a shortcut dictionary of that name (if stored).

+


+

name - Symbol or String.

+

+


+

*copyCurrentDict (name)

+

+

Returns a copy of the current shortcut dictionary of that name.

+


+

name - Symbol or String.

+

+


+

*copyAllDicts

+

+

Returns an IdentityDictionary of copies of all stored shortcut dictionaries.

+

+

+

*post (name)

+

+

Posts the shortcut dictionary of that name (if stored).

+


+

name - Symbol or String.

+

+

+

*postCurrent

+

+

Posts the current shortcut dictionary.

+

+

+

*postAll

+

+

Posts all shortcut dictionaries.

+

+

+

*makeCurrent (name)

+


+

Makes the shortcut dictionary of that name current (if stored).

+

+

name - Symbol or String.

+

+


+

*on

+

+

Turns on the shortcut mechanism, making it ready for events / patterns to be played.

+

Also invokes prefixEventTypes.

+


+


+

*off

+

+

Turns the shortcut mechanism off.

+


+


+

*prefixEventTypes

+

+

Puts the remapping function before all event type functions. Therefore a newly defined event type won't work

+

with shortcuts before this has been called (directly or via on).

+


+

+

*current

+

+

Returns the Symbol of the current shortcut dictionary.

+

+

+

*dictNames

+

+

Returns the Symbols of all shortcut dictionaries.

+

+


+

*state

+

+

Returns the current state (\on or \off).

+

+

+


+

+

Examples

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// turn shortcuts on

+


+

EventShortcuts.on

+


+


+

// post all, right now only \default exists

+


+

EventShortcuts.postAll

+


+


+

// play an Event with midinote 70

+


+

(m: 70).play

+


+


+

// play a Pbind

+


+

(

+

Pbind(

+

\m, Pwhite(60, 90, 20) + [0, -7], // midinote

+

\p, Pwhite(-1.0, 1), // pan

+

\l, 3, // legato

+

\s, 0.1, // strum

+

\d, 0.5 // dur

+

).play

+

)

+


+


+


+

// define new dictionary based on \default with two different shortcuts

+


+

EventShortcuts.addOnBase(\default, \mine, (s: \scale, t: \ctranspose))

+


+


+

// it isn't current yet, make it 

+


+

EventShortcuts.makeCurrent(\mine)

+


+


+

// play Pbind with new shortcuts, using key/value notation here

+


+

(

+

p = Pbind(*[

+

de: Prand([[0, 1, 26, 27], [-6, 4, 10], [0, 8, 14]], inf), // degree

+

t: Pwhite(0, 1) + Pwrand([0, -10, 10], [0.9, 0.05, 0.05], 200), // ctranspose

+

d: 0.2,  // dur

+

s: Scale.chromatic24 // scale

+

]).play

+

)

+


+


+

// define a SynthDef

+


+

(

+

SynthDef(\test, { |out = 0, freq = 440, width = 0.5, amp = 0.05, gate = 1, 

+

att = 0.05, rel = 1, pan = 0|

+

Out.ar(out, Pan2.ar(Pulse.ar(freq, width, amp), pan) * 

+

EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction:2)

+

)

+

}).add

+

)

+


+


+

// you can also define shortcuts for synthdef args 

+


+

(

+

EventShortcuts.addOnBase(\mine, \mine, (w: \width, r: \rel), true);

+

EventShortcuts.makeCurrent(\mine);

+

)

+


+


+

(

+

Pbind(*[

+

i: \test, // instrument

+

n: Prand([0, 4, 7], inf), // note 

+

o: Pwhite(5, 6), // octave

+

dt: Pwhite(0, 20), // detune (in cent)

+

l: 0.2, // legato

+

d: 0.2, // dur

+

w: Pseq((5, 10..40)/100, 4), // width (synth arg)

+

r: Pseq([0.1, 0.5], inf), // rel (synth arg)

+

]).play

+

)

+


+


+

// works also with other event patterns: Pmono, PmonoArtic, Pbindef

+


+

(

+

Pmono(\default, *[

+

d: 0.03, // dur

+

a: 0.3, // amp

+

dt: Pseq([0, 10], inf),  // detune in Hz

+

p: Pseq((-100, -95..100)/100, 1)  // pan

+

]).play

+

)

+


+


+

// further shortcuts for playing events and patterns are collected here: Other event and pattern shortcuts

+

// e.g. you can directly play a Pbind derived from an Array:

+


+

(

+

[

+

n: Pshuf((1..12)), // note 

+

d: 0.5, // dur

+

l: 3, // legato 

+

o: Pwhite(4, 7) // octave

+

].pp

+

)

+


+

// also possible with Pbindef, though you shouldn't change current shortcut

+

// if you still want to refer later on to a Pbindef defined before the change

+


+


+

(

+

Pbindef(\x, *[

+

d: Prand([1,1,2]/5, inf), // dur

+

m: Pwhite(50, 80), // midinote

+

ct: Prand([[0, 4], [0, 5]], inf) // ctranspose

+

]).play

+

)

+


+

Pbindef(\x, \d, Prand([1,1,1,2,3]/7, inf))

+


+

Pbindef(\x, \ct, [0, 5, 8, 13, 16])

+


+

Pbindef(\x).stop;

+


+


+

// turns off and ensures that default shortcuts are active when EventShortcuts is 

+

// turned on next time in this session 

+


+

(

+

EventShortcuts.off;

+

EventShortcuts.makeCurrent(\default);

+

)

+


+


+ + diff --git a/Help/Fb1.html b/Help/Fb1.html new file mode 100755 index 0000000..5c3cc15 --- /dev/null +++ b/Help/Fb1.html @@ -0,0 +1,1585 @@ + + + + + + + + + + + +

Fb1 single sample feedback / feedforward pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Fb1 provides an interface for single sample feedback and feedforward at audio and control rate, the defining relation with (formal) access to previous samples is passed as a Function, which might involve additional UGens. Fb1.ar works with arbitrary blockSizes and also allows to refer to samples earlier than one blockSize before. This includes linear filter definitions of arbitrary length with dynamic coefficients as well as all kinds of nonlinear calculations of feedback and feedforward data (FOS and SOS UGens cover the linear case with lengths 1 and 2, LTI the general linear case). 

+


+

Fb1 at control rate exists since miSCellaneous v0.22, for compatibility reasons I left the convention that Fb1.new generates an ar UGen, so Fb1.new is now equivalent to Fb1.ar and Fb1.kr is possible in addition (See Ex.5). Fb1 is the base of an ordinary differential equation integrator framework for initial value problems, that also came with v0.22, see Fb1_ODE help for an introduction.

+


+

HISTORY AND CREDITS: There have been long discussions on single-sample feedback in SC. The most simple, but CPU-intense strategy is setting the server's blockSize to 1. Julian Rohrhuber gave a number of examples with Dbufrd / Dbufwr. SC's folder 'Examples' contains the files single_sample_feedback.scd and single_sample_feedback_02.scd. Special solutions are also possible with Delay1, Delay2 and other UGens. This particular implementation is based on Nathaniel Virgo's suggestion of iteratively writing to and reading from Buffers of blockSize – big credit for this! See also Nathaniel Virgo's Feedback quark for his feedback classes Fb and FbNode. Thanks also to James Harkins for his remarks on graph order. See Ex.1a for the basic feedback implementation principle. I implemented the ar feedforward option by temporary buffers for ar writing and kr reading, the feedback / feedforward relation can now be passed via a Function with 'in' and 'out' args. That way the syntax looks very similar to the common notations used for filter descriptions and also applies directly to the multichannel case. Most other options of Fb1 are for special multichannel handling and differentiated lookback definitions, which can help to save a lot of UGens.

+


+

WARNING: Be careful with amplitudes, feedback can become loud! It is highly recommended to take measures to avoid blowup, e.g. by limiting operators (tanh, softclip, distort) and/or using MasterFX from the JITLibExtensions quark. Also consider that short iteration cycles can produce loud high pitches, wrapping lopass filters is useful! 

+


+

NOTE: The convenience of direct definition of the feedback / feedforward relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. You might also want to experiment with blockSizes smaller than 64 and larger than 1 (e.g. 8, 16 or 32). Check the graphOrderType arg, other values might cause considerable CPU saving and/or shortening of synthdef compile time. 

+


+

See also: GFIS, Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

Creation / Class Methods

+

+

*new (func, in, outSize = 0, inDepth = 1, outDepth = 2, inInit, outInit, blockSize = 64, blockFactor = 1, graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+


+

Creates a new Fb1 ar object.

+

+

func - The Function to define the feedback / feedforward relation. The Function should take 

+

the two arguments 'in' and 'out', both understood as nested multichannel signals,

+

additionally a block index is passed (Ex. 3e). 

+

Each 'in' / 'out' item of the arrays represents current or previous samples,

+

for all points in time the samples are passed in specific array shapes,

+

which are determined by the shapes of in and outSize.

+

Allowed are pure signals (size = 0) and nested SequenceableCollections at maximum:

+

e.g. outSize can be 0, 3, or [0, 2, 5], accordingly in signals can be of sizes 

+

0, i or [i1, ... , in] with i, ij >= 0.

+

Note that 'in' and 'out' only formally represent ar feedback and feedforward signals,

+

technically kr UGens (BufRd.kr) are passed, the ar signals are reconstructed at the end 

+

by reading (arrays of) Buffers.

+

The Function should return the multichannel UGen to be referred to with 'out',

+

the shapes of the returned UGens and outSize must be the same.

+

Furthermore the meaning of 'in' and 'out' depends on the inDepth and outDepth arguments.

+

If an Integer is passed to them (default), the indices of 'in' resp. 'out'  correspond to the 

+

lookback indices:

+

E.g. out[1] refers to the last output sample(s) (of shape outSize), out[2] to the output sample(s) before 

+

the last output sample(s) etc. This is compliant with the convention of writing out[i-1], out[i-2] etc., 

+

out[0] refers to out[i-blockSize]. 

+

For a multichannel 'in' / 'out' signal, depth can be differentiated, which saves UGens 

+

in the case of "gaps" in the recursion:

+

E.g. for a three-channel out signal outDepth can look like [3, [7, 18], [2, 5, 6]].

+

Then out[1] is a three-channel signal, whereby out[1][0] corresponds to out[i-1] of the

+

first, out[1][1] to out[i-18] of the second and out[1][2] to out[i-5] of the third component.

+

If the size of inDepth / outDepth is smaller than outSize, wrapping is applied.

+

As a result double-bracketing can be used to define specific lookback indices

+

for all components of the multichannel signal:

+

E.g. if outDepth equals [[7, 18]] for a three-channel signal then out[0] means 

+

the three-channel signal out[i-7] and out[1] means out[i-18].

+

See Ex. 3a for multichannel feedback / feedforward.

+

in - A single ar input signal or a SequenceableCollection of ar input signals to be referred to 

+

with func (feedforward data). See Ex. 3a for multichannel feedback / feedforward.

+

outSize - Integer or SequenceableCollection thereof, 

+

the size(s) defined by the UGen(s) returned by func. 

+

It's the user's responsibilty to pass the correct size(s)! 

+

Defaults to 0.

+

inDepth - Integer or SequenceableCollection of Integers or SequenceableCollections thereof, 

+

this determines the behaviour of func (see there).

+

If an Integer is passed, it means the maximum storage size for feedforward data. 

+

If a SequenceableCollection is passed, lookback indices for feedforward data 

+

can be differentiated, its items can again be Integers or SequenceableCollections (see func). 

+

Usually the inner SequenceableCollections should be ordered, but this is not compulsory.

+

Defaults to 1 (no lookback). See Ex. 3c.

+

outDepth - Integer or SequenceableCollection of Integers or SequenceableCollections thereof, 

+

this determines the behaviour of func (see there).

+

If an Integer is passed, it means the maximum storage size for feedback data. 

+

If a SequenceableCollection is passed, lookback indices for feedback data 

+

can be differentiated, its items can again be Integers or SequenceableCollections (see func). 

+

Usually the inner SequenceableCollections should be ordered, but this is not compulsory.

+

Defaults to 2 (look back to last sample at maximum). See Ex. 3c.

+

inInit - Number or SequenceableCollection, feedforward init data.

+

If a Number is passed, it means the previous init value for the calculation of the first sample(s),

+

if the size of in is larger than 1, this init value is taken for all components of the multichannel signal.

+

If a SequenceableCollection is passed, this differentiates the init values 

+

for a multichannel signal 'in' used by func. Then the components must be Numbers 

+

(again defining one init value) or SequenceableCollections, which

+

define a lookback collection: first Number is the previous value, second the value before and so on.

+

If the size of inInit is smaller than the size of in, wrapping is applied, that way a double-bracket array, 

+

e.g. [[3, 0, 1]], defines the same init sequence for all components of a multichannel in. See Ex. 3b.

+

outInit - Number or SequenceableCollection, feedback init data.

+

If a Number is passed, it means the previous init value for the calculation of the first sample(s),

+

if outSize is larger than 1, this init value is taken for all components of the 

+

multichannel signal 'out' used by func. 

+

If a SequenceableCollection is passed, this differentiates the init values 

+

for this multichannel signal. Then the components must be Numbers (again defining one init value) 

+

or SequenceableCollections, which define a lookback collection: 

+

first Number is the previous value, second the value before and so on.

+

If the size of outInit is smaller than outSize, wrapping is applied, that way a double-bracket array, 

+

e.g. [[3, 0, 1]], defines the same init sequence for all components of the multichannel signal 

+

'out' used by func. See Ex. 3b.

+

blockSize - Integer, this should be the server blockSize. It's the user's responsibility to pass

+

the correct number. However it might be interesting to experiment with other values.

+

Defaults to 64. See Ex. 3d.

+

blockFactor - Integer. For a value > 1 this allows for lookback indices larger than blockSize, up to 

+

blockSize * blockFactor - 1. It's the user's responsibility to pass correct Integers in this case. 

+

Defaults to 1. See Ex. 3d.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens and in all my examples I didn't encounter cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output.

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+

 

+

*ar (func, in, outSize = 0, inDepth = 1, outDepth = 2, inInit, outInit, blockSize = 64, blockFactor = 1, graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+


+

equivalent to *new

+


+


+

*kr (func, in, outSize = 0, inDepth = 1, outDepth = 2, inInit, outInit, graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+


+

Creates a new Fb1 kr object.

+

+

func - The Function to define the feedback / feedforward relation. The Function should take 

+

the two arguments 'in' and 'out', both understood as nested multichannel signals,

+

additionally a block index is passed (Ex. 3e). 

+

Each 'in' / 'out' item of the arrays represents current or previous control samples,

+

for all points in time the control samples are passed in specific array shapes,

+

which are determined by the shapes of in and outSize.

+

Allowed are pure signals (size = 0) and nested SequenceableCollections at maximum:

+

e.g. outSize can be 0, 3, or [0, 2, 5], accordingly in signals can be of sizes 

+

0, i or [i1, ... , in] with i, ij >= 0.

+

Note that 'in' and 'out' only formally represent feedback and feedforward signals,

+

technically kr UGens (BufRd.kr) are passed.

+

The Function should return the multichannel UGen to be referred to with 'out',

+

the shapes of the returned UGens and outSize must be the same.

+

Furthermore the meaning of 'in' and 'out' depends on the inDepth and outDepth arguments.

+

If an Integer is passed to them (default), the indices of 'in' resp. 'out'  correspond to the 

+

lookback indices:

+

E.g. out[1] refers to the last control output sample(s) (of shape outSize), out[2] to the control output sample(s) before 

+

the last control output sample(s) etc. This is compliant with the convention of writing out[i-1], out[i-2] etc.

+

For a multichannel 'in' / 'out' signal, depth can be differentiated, which saves UGens 

+

in the case of "gaps" in the recursion:

+

E.g. for a three-channel out signal outDepth can look like [3, [7, 18], [2, 5, 6]].

+

Then out[1] is a three-channel signal, whereby out[1][0] corresponds to out[i-1] of the

+

first, out[1][1] to out[i-18] of the second and out[1][2] to out[i-5] of the third component.

+

If the size of inDepth / outDepth is smaller than outSize, wrapping is applied.

+

As a result double-bracketing can be used to define specific lookback indices

+

for all components of the multichannel signal:

+

E.g. if outDepth equals [[7, 18]] for a three-channel signal then out[0] means 

+

the three-channel signal out[i-7] and out[1] means out[i-18].

+

See Ex. 3a for multichannel feedback / feedforward.

+

in - A single kr input signal or a SequenceableCollection of kr input signals to be referred to 

+

with func (feedforward data). See Ex. 3a for multichannel feedback / feedforward.

+

outSize - Integer or SequenceableCollection thereof, 

+

the size(s) defined by the UGen(s) returned by func. 

+

It's the user's responsibilty to pass the correct size(s)! 

+

Defaults to 0.

+

inDepth - Integer or SequenceableCollection of Integers or SequenceableCollections thereof, 

+

this determines the behaviour of func (see there).

+

If an Integer is passed, it means the maximum storage size for feedforward data. 

+

If a SequenceableCollection is passed, lookback indices for feedforward data 

+

can be differentiated, its items can again be Integers or SequenceableCollections (see func). 

+

Usually the inner SequenceableCollections should be ordered, but this is not compulsory.

+

Defaults to 1 (no lookback). See Ex. 3c.

+

outDepth - Integer or SequenceableCollection of Integers or SequenceableCollections thereof, 

+

this determines the behaviour of func (see there).

+

If an Integer is passed, it means the maximum storage size for feedback data. 

+

If a SequenceableCollection is passed, lookback indices for feedback data 

+

can be differentiated, its items can again be Integers or SequenceableCollections (see func). 

+

Usually the inner SequenceableCollections should be ordered, but this is not compulsory.

+

Defaults to 2 (look back to last control sample at maximum). See Ex. 3c.

+

inInit - Number or SequenceableCollection, feedforward init data.

+

If a Number is passed, it means the previous init value for the calculation of the first control sample(s),

+

if the size of in is larger than 1, this init value is taken for all components of the multichannel signal.

+

If a SequenceableCollection is passed, this differentiates the init values 

+

for a multichannel signal 'in' used by func. Then the components must be Numbers 

+

(again defining one init value) or SequenceableCollections, which

+

define a lookback collection: first Number is the previous value, second the value before and so on.

+

If the size of inInit is smaller than the size of in, wrapping is applied, that way a double-bracket array, 

+

e.g. [[3, 0, 1]], defines the same init sequence for all components of a multichannel in. See Ex. 3b.

+

outInit - Number or SequenceableCollection, feedback init data.

+

If a Number is passed, it means the previous init value for the calculation of the first control sample(s),

+

if outSize is larger than 1, this init value is taken for all components of the 

+

multichannel signal 'out' used by func. 

+

If a SequenceableCollection is passed, this differentiates the init values 

+

for this multichannel signal. Then the components must be Numbers (again defining one init value) 

+

or SequenceableCollections, which define a lookback collection: 

+

first Number is the previous value, second the value before and so on.

+

If the size of outInit is smaller than outSize, wrapping is applied, that way a double-bracket array, 

+

e.g. [[3, 0, 1]], defines the same init sequence for all components of the multichannel signal 

+

'out' used by func. See Ex. 3b.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens and in all my examples I didn't encounter cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output.

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+


+

+

Overview - what can / cannot be done ?

+


+

// What can be done:

+


+

// The feedback / feedforward relation is defined within func,

+

// it's important to note that this Function is applied in a very special way

+

// to build the feedback relation into the synthdef graph.

+


+

// Let n be the given blockSize, then

+


+

// 1.) ar / kr: func (only formally) takes over previous (multichannel) out samples for calculation of

+

// next (multichannel) out samples via its 'out' arg,

+

// technically BufRd.krs are passed to 'out' arg, in the ar case signals are reconstructed thereafter

+

// 2.) ar: func is applied n times to establish the iteration in the synthdef graph

+

// 3.) ar / kr: unary and binary operators are the basic tools for this calculation

+

// 4.) ar / kr: func can take over modulating kr UGens from outside via simple reference,

+

// for ar no linear interpolation in this case though, you might therefore consider (5)

+

// 5.) ar / kr: func can take over feedforward UGens with reference to their past data from outside via Fb1's and func's 'in' arg

+

// 6.) ar / kr: func can contain explicitely defined kr UGens.

+

// ar: note that for every UGen in func, n instances are built into the SynthDef graph!

+

// 7.)ar / kr: kr UGens in func can be applied to data passed via 'in' or 'out'

+

// 8.)ar: func's index argument can be used to specify the feedback / feedforward relation per block index

+


+


+

// What cannot / shouldn't be done (ar case considerations)

+


+

// Writing ar UGens in func that produce a time-varying signal itself

+

// (e.g. SinOsc.ar, in contrast to SinOsc.kr and operator UGens like '+', '*' etc.) -

+

// instead, if such ar UGens aren't applied to data from inside func, 

+

// they can be passed via Fb1's and func's 'in' arg.

+

// It remains the case of such ar UGens that should process data that is provided by func

+

// (e.g. letting the fb out modulate a parameter of a VarSaw.ar). 

+

// This is currently not possible and I don't have a clear picture if and how 

+

// it would be possible at all or if it would make much sense.

+


+


+


+

Examples 1) Proof of concept

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// Examples 1b-1d are just a comparison of standard filters vs. explicit definition with Fb1

+

// to show its functioning.

+

// Mostly there is no benefit in doing so in practice as standard filters UGens need less ressources.

+

// The real power of Fb1 lies in the potential to define nonlinear feedback and feedforward relations (2a-2f).

+

// Other than that you can use it to define higher order linear filters for which no classes exist.

+


+

// check blockSize before

+


+

(

+

if (s.options.blockSize != 64) {

+

s.options.blockSize = 64;

+

s.quit.reboot;

+

}

+

)

+


+

Ex.1a) Basic principle

+

+

// The original form of the following example is by Nathaniel Virgo 

+

// and shows the underlying principle for feedback alone.

+

// Succesively Buffers are set with new values at kr,

+

// at the end buffers are read with an ar Phasor,

+

// thereby the order of UGens is crucial.

+

// As James Harkins remarked in the below thread,

+

// plugging the writers into the final reader forces it,

+

// it can be done with summing, but other operations than '+' are also possible.

+


+

// The example also works without this precautionary measure, at least on OSX, SC 3.9.3.

+

// The option graphOrderType allows to turn forced ordering off or to choose an

+

// alternative order-forcing operation, see Ex. 4.

+


+

// https://www.listarc.bham.ac.uk/lists/sc-users-2011/msg01337.html

+

// https://www.listarc.bham.ac.uk/lists/sc-users-2011/msg01363.html

+


+


+

(

+

x = {

+

var buf1 = LocalBuf(64);

+

var buf2 = LocalBuf(64);

+

var x1, x2;

+

var writer_1 = DC.ar(0);

+

var writer_2 = DC.ar(0);

+

SetBuf(buf1, [1], 63); 

+

SetBuf(buf2, [0], 63);

+

x1 = BufRd.kr(1, buf1, 63);

+

x2 = BufRd.kr(1, buf2, 63);

+

64.do { |i|

+

x1 = x1 + (0.2 * x2);

+

x2 = tanh(x2 * 1.2 - (0.1 * x1));

+


+

writer_1 = writer_1 + BufWr.kr(x1, buf1, i);

+

writer_2 = writer_2 + BufWr.kr(x2, buf2, i);

+

};

+

// '<!' ensures that BufWrs are placed before the final reader

+

BufRd.ar(1, [buf1 <! writer_1, buf2 <! writer_2], Phasor.ar(0, 1, 0, 64)) * 0.1;

+

}.play;

+

)

+


+


+

x.release

+


+


+

// same written with Fb1

+

// per default LeakDC is applied, turn off here

+


+

(

+

y = {

+

Fb1({ |in, out|

+

var x1, x2; // define variables to adapt naming convention of above

+

// refer to last out samples

+

#x1, x2 = out[1];

+

x1 = x1 + (0.2 * x2);

+

x2 = tanh(x2 * 1.2 - (0.1 * x1));

+

[x1, x2]

+

}, outSize: 2, outInit: [1, 0], leakDC: false) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+

// check if it's really the same, the difference should run silently (Fb1 without LeakDC)

+


+

(

+

z = {

+

var buf1 = LocalBuf(64);

+

var buf2 = LocalBuf(64);

+

var x1, x2;

+

var writer_1 = DC.ar(0);

+

var writer_2 = DC.ar(0);

+

SetBuf(buf1, [1], 63); 

+

SetBuf(buf2, [0], 63);

+

x1 = BufRd.kr(1, buf1, 63);

+

x2 = BufRd.kr(1, buf2, 63);

+


+

64.do { |i|

+

x1 = x1 + (0.2 * x2);

+

x2 = tanh(x2 * 1.2 - (0.1 * x1));

+


+

writer_1 = writer_1 + BufWr.kr(x1, buf1, i);

+

writer_2 = writer_2 + BufWr.kr(x2, buf2, i);

+

};

+

+

BufRd.ar(1, [buf1 <! writer_1, buf2 <! writer_2], Phasor.ar(0, 1, 0, 64)) -

+

Fb1({ |in, out|

+

var x1, x2; // define variables to adapt naming convention of above

+

#x1, x2 = out[1];

+

x1 = x1 + (0.2 * x2);

+

x2 = tanh(x2 * 1.2 - (0.1 * x1));

+

[x1, x2]

+

}, outSize: 2, outInit: [1, 0], leakDC: false) * 0.1;

+

}.play;

+

)

+


+

z.release

+


+


+


+

Ex.1b) OnePole

+

+

// OnePole as lopass

+


+

s.freqscope;

+


+

x = { OnePole.ar(WhiteNoise.ar(0.3), 0.95) }.play;

+


+

x.release

+


+

// OnePole is implemented by out(i) = ((1 - abs(coef)) * in(i)) + (coef * out(i-1))

+

// so it can be written with Fb1

+


+

y = { Fb1({ |in, out| (in[0] * 0.05) + (out[1] * 0.95) }, WhiteNoise.ar(0.3), leakDC: false) }.play

+


+

y.release

+


+


+

// difference check: this falls silent (Fb1 without LeakDC)

+


+

(

+

z = {

+

var src = WhiteNoise.ar(0.5);

+

Fb1({ |in, out| (in[0] * 0.05) + (out[1] * 0.95) }, src, leakDC: false) - OnePole.ar(src, 0.95)

+

}.play

+

)

+


+

z.release

+


+


+

// stereo case: 'in' is passed a stereo noise,

+

// in addition we have to pass outSize: 2,

+

// then the Function can be written in the same way

+

// in[0] and out[1] now mean stereo signals

+


+

u = { Fb1({ |in, out| (in[0] * 0.05) + (out[1] * 0.95) }, WhiteNoise.ar(0.3!2), 2) }.play

+


+

u.release

+


+


+


+

// difference check with dynamic coefficient

+

// pass the ar signal via Fb1's 'in' arg

+

// difference nearly 0, even with fast modulation

+


+

(

+

v = {

+

var src = WhiteNoise.ar(0.5);

+

var mod = LFDNoise3.ar(50).range(0.7, 0.99);

+

(

+

Fb1({ |in, out| 

+

var src, mod;

+

#src, mod = in[0];

+

(src * (1 - mod)) + (out[1] * mod) 

+

}, [src, mod], leakDC: false) -

+

OnePole.ar(src, mod)

+

).poll

+

}.play

+

)

+


+

v.release

+


+


+


+

// Now check same with kr signal for coefficient,

+

// here we can directly take over the signal in func,

+

// difference is not zero though, because OnePole

+

// does linear interpolation with mod (Fb1 doesn't)!

+


+

(

+

w = {

+

var src = WhiteNoise.ar(0.5);

+

var mod = LFDNoise3.kr(50).range(0.7, 0.99);

+

(

+

Fb1({ |in, out| (in[0] * (1 - mod)) + (out[1] * mod) }, src, leakDC: false) -

+

OnePole.ar(src, mod)

+

).poll

+

}.play

+

)

+


+

w.release

+


+


+

// proof of concept with kr:

+

// If OnePole doesn't interpolate (as with Latch),

+

// signals are the same

+


+


+

(

+

q = {

+

var src = WhiteNoise.ar(0.5);

+

var mod = LFDNoise3.kr(50).range(0.7, 0.99);

+

(

+

Fb1({ |in, out| (in[0] * (1 - mod)) + (out[1] * mod) }, src, leakDC: false) -

+

OnePole.ar(src, Latch.ar(mod, TDuty.ar(ControlDur.ir)))

+

).poll

+

}.play

+

)

+


+

q.release

+


+


+
Ex.1c) SOS

+

+

// SOS as bandreject, note its convention:

+

// SOS.ar(in, a0, a1, a2, b1, b2, mul, add)

+

// out(i) = (a0 * in(i)) + (a1 * in(i-1)) + (a2 * in(i-2)) + (b1 * out(i-1)) + (b2 * out(i-2))

+


+

s.freqscope;

+


+

(

+

x = {

+

var a = [-0.6, 0.5, -0.7]; // feedforward coefficients a0, a1, a2

+

var b = [0.5, -0.1]; // feedback coefficients b1, b2

+

var src = Saw.ar(200, 0.1);

+

SOS.ar(src, *(a ++ b))

+

}.play

+

)

+


+

x.release

+


+

// written with Fb1

+


+

(

+

y = {

+

var a = [-0.6, 0.5, -0.7];

+

var b = [0.5, -0.1];

+

var src = Saw.ar(200, 0.1);

+

// out[0] (= out[i-blockSize]) is passed formally to allow taking over the usual index convention

+

// here we drop it as b1 = b[0] and b2 = b[1]

+

// as we look back two samples for feedforward and feedback we need to pass depths 3

+

Fb1({ |in, out| (in * a).sum + (out.drop(1) * b).sum }, src, 0, 3, 3, leakDC: false)

+

}.play

+

)

+


+

y.release

+


+


+

// difference check: this falls silent

+


+

(

+

z = {

+

var a = [-0.6, 0.5, -0.7];

+

var b = [0.5, -0.1];

+

var src = Saw.ar(200, 0.1);

+

(

+

Fb1({ |in, out| (in * a).sum + (out.drop(1) * b).sum }, src, 0, 3, 3, leakDC: false) -

+

SOS.ar(src, *(a ++ b)) // '*' splits the array into single items needed as UGen args

+

).poll 

+

}.play

+

)

+


+

z.release

+


+


+

Ex.1d) LTI

+


+
// You need to have the SC-3 plugins installed in order to use LTI,

+

// which is part of Nick Collins' SLUGens.

+


+

// Example with coefficients from Nick Collins' helpfile,

+

// here 'a' is used for feedback coefficients.

+


+

// LTI needs data in buffers

+


+

(

+

a = [0.02, -0.01]; // feedback coefficients

+

b = [1, 0.7, 0, 0, 0, 0, -0.8, 0, 0, 0, 0, 0.9] ++

+

[0, 0, 0, -0.5, 0, 0, 0, 0, 0, 0, 0.25, 0.1, 0.25]; // feedforward coefficients

+

c = Buffer.sendCollection(s, a, 1);

+

d = Buffer.sendCollection(s, b, 1);

+

)

+


+

x = { LTI.ar(Saw.ar(50, 0.1), c.bufnum, d.bufnum) }.play

+


+

x.release

+


+


+

// Because of the large inDepth (25 !) a straight takeover of data is very CPU-demanding with Fb1

+


+

(

+

y = {

+

var src = Saw.ar(50, 0.1);

+

Fb1({ |in, out| (in * b).sum + (out.drop(1) * a).sum }, src, 0, b.size, 3, leakDC: false)

+

}.play

+

)

+


+

y.release

+


+


+

// This is an example, where passing lookback indices as depth arg helps a lot (more than 1000 UGens less!)

+


+

(

+

z = {

+

var src = Saw.ar(50, 0.1);

+

var ff = b.reject(_ == 0); // [1, 0.7, -0.8, 0.9, -0.5, 0.25, 0.1, 0.25]

+

+

// for SC < 3.7 you can write (0..b.size-1).select { |i| b[i] != 0 }

+

var indices = b.selectIndices(_ != 0); // [0, 1, 6, 11, 15, 22, 23, 24]

+

+

Fb1({ |in, out| (in * ff).sum + (out.drop(1) * a).sum }, src, 0, [indices], 3, leakDC: false)

+

}.play

+

)

+


+


+

z.release

+


+


+

// difference check, run silently

+


+

(

+

u = {

+

var src = Saw.ar(50, 0.1);

+

var ff = [1, 0.7, -0.8, 0.9, -0.5, 0.25, 0.1, 0.25];

+

var indices = [0, 1, 6, 11, 15, 22, 23, 24];

+

(Fb1({ |in, out| (in * ff).sum + (out.drop(1) * a).sum }, src, 0, [indices], 3, leakDC: false) -

+

LTI.ar(src, c.bufnum, d.bufnum)).poll

+

}.play

+

)

+


+

u.release

+


+

// The filter alternatives with Fb1 mainly make sense in the higher order case when coefficients should be modulated 

+


+


+
Examples 2) Nonlinear feedback operations

+


+

// This is an interesting field of exploration as it cannot easily be done with SC otherwise.

+

// Here the time-varying potential of unary and binary operators comes into play,

+

// normally they are applied to time-varying signals, but here their iteration on a

+

// single-sample base is itself an essential part of producing the variation in time.

+

// Good candidates are already simple operators and their combinations, also with + and -, 

+

// e.g. *, /, **, %, trigonometric operators etc.

+


+


+

Ex.2a) %

+

+

s.scope

+


+

// start fb fx Synth

+


+(

+

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

+


+


+

y = {

+

var inSig = In.ar(~bus, 2);

+

var lfo = SinOsc.ar(0.1).linexp(-1, 1, 50, 500);

+

LPF.ar(

+

Fb1({ |in, out|

+

(out[2] * 0.7) + // factors > 1 blow up !

+

// only the next line is limited with softclip

+

+

// in[0][0] is the current stereo signal from the bus

+

// in[1][0] is the previous

+

// in[0][1] is the current mono lfo, passed with the 'in' arg

+

+

// func returns a stereo signal, so outSize must be passed 2

+

// inDepth [2, 1] because we use inSig[0], inSig[1] and lfo[0]

+

// outDepth 3 because we use out[2]

+

// note that it would be cheaper to use out[0] and outDepth: [[2]],

+

// but a bit more difficult to read

+

+

((in[0][0] - in[1][0]) % 0.01 * in[0][1]).softclip

+

}, [inSig, lfo], 2, [2, 1], 3

+

), 15000) * 0.1

+

}.play

+

)

+


+

// start source

+


+

x = { Out.ar(~bus, SinOsc.ar([60, 60.1]) * EnvGate.new) }.play

+


+

// stop source and start new one

+


+

x.release

+


+

x = { Out.ar(~bus, Saw.ar(SinOsc.ar(0.07).linlin(-1, 1, [100, 100.01], 100.2) * EnvGate.new)) }.play

+


+


+

x.release

+


+

(

+

y.free;

+

~bus.free;

+

)

+


+


+

Ex.2b) sin

+

+

// sin can work as a limiter as well as a nonlinear dynamics engine,

+

// here it causes a wavefolding-like effect

+


+

s.scope

+


+

// start fb fx Synth

+


+


+

(

+

~bus = Bus.audio(s, 1);

+


+

y = {

+

var inSig = In.ar(~bus);

+

var lfo = SinOsc.ar(0.1, -pi/2).linexp(-1, 1, [5, 10], 100) * 100;

+

LPF.ar(

+

Fb1({ |in, out|

+

// here out[0] refers to out[i-2] because of outDepth: [[2]]

+

(out[0] * 0.7) + // factors > 1 blow up !

+

// here in[0][0] and in[1][0] are current and previous mono inSig,

+

// but in[0][1] is stereo, so again a stereo signal is returned by func,

+

// which must be indicated with the outSize arg

+

((in[0][0] - in[1][0]) * in[0][1]).sin

+

}, [inSig,  lfo], 2, [2, 1], [[2]]

+

) * 0.05, 15000)

+

}.play

+

)

+


+


+

// start source

+


+

x = { Out.ar(~bus, SinOsc.ar(60) * EnvGate.new) }.play;

+


+

x.release;

+


+

// stop source and start new one

+


+

x = { Out.ar(~bus, Saw.ar(SinOsc.ar(0.05).linlin(-1, 1, 100, 100.02) * EnvGate.new)) }.play

+


+

x.release

+


+

(

+

y.free;

+

~bus.free;

+

)

+


+


+

Ex.2c) * 

+

+

// rather irrational concatenation of simple operations

+

// depth changes cause frequency changes

+


+


+

s.scope

+


+

// start fb fx Synth

+


+(

+

~bus = Bus.audio(s, 1);

+


+

y = {

+

var inSig = In.ar(~bus);

+

var lfo = { LFDNoise3.ar(0.07).linexp(-1, 1, 1, 5) } ! 2;

+

var i = Demand.kr(Dust.kr(0.5), 0, Dxrand((0..2), inf));

+

var sig = Fb1({ |in, out|

+

(

+

in[0][1] * (

+

in[0][0] * 0.12 + (

+

// changes between out[i-23], out[i-41] and out[i-60] cause frequency changes,

+

// Select depends on a signal from outside, not previous samples as in Ex. 2f

+

(in[1][0].squared - Select.kr(i, out).squared).sqrt

+

)

+

) 

+

).tanh

+

}, [inSig, lfo], 2, [2, 1], [[23, 41, 60]]) * 0.1;

+

// add frequency modulation by delay modulation

+

// lopass filtering with lag

+

DelayC.ar(sig, 0.2, LFDNoise3.ar(1).range(0.01, 0.1)).lag(0.0005)

+

}.play

+

)

+


+

// start source

+


+

x = { Out.ar(~bus, LFTri.ar(LFDNoise0.ar(5).exprange(1, 100)) * EnvGate.new) }.play;

+


+

x.release

+


+

(

+

y.free;

+

~bus.free;

+

)

+


+


+

Ex.2d) / 

+

+


+

// With divisions we must avoid division by zero resp. blowup, here it's max in the divisor.

+

// The example also establishes a cross-feedback of the two channels by using reverse.

+


+

s.scope

+


+

// start fb fx Synth

+


+(

+

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

+


+

y = {

+

var inSig = In.ar(~bus, 2);

+

var lfo = LFDNoise3.ar(1).linexp(-1, 1, 0.2, 10);

+

LPF.ar(

+

Fb1({ |in, out|

+

(in[1][0] * in[0][1] / max(0.001, (in[1][0] - out[1].reverse).abs)).tanh

+

}, [inSig, lfo], 2, [2, 1], 2

+

), 15000) * 0.1

+

}.play

+

)

+


+

// start source

+


+

x = { Out.ar(~bus, SinOsc.ar(LFDNoise3.ar(0.1!2).range(100, 101)) * EnvGate.new) }.play

+


+

x.release

+


+

(

+

y.free;

+

~bus.free;

+

)

+


+


+

Ex.2e) **

+

+

// exponentiation can also be interesting

+

// here an area of instability is crossed by a stereo lfo 

+


+

s.scope

+


+

// start fb fx Synth

+


+(

+

~bus = Bus.audio(s, 1);

+


+

y = {

+

var inSig = In.ar(~bus);

+

var lfo = { LFDNoise3.ar(0.5).linexp(-1, 1, 0.1, 150) } ! 2;

+


+

Fb1({ |in, out|

+

in[1][0] * 0.07 +

+

// out[0] refers to out[i-2] because of outDepth: [[2]]

+

(2 ** (in[1][0] - out[0] * in[0][1]).abs).tanh

+

}, [inSig, lfo], 2, [2, 1], [[2]]) *

+

// avoid bump at start 

+

EnvGen.ar(Env.asr(2))

+

}.play

+

)

+


+


+

// start source

+


+

x = { Out.ar(~bus, LFTri.ar(60) * EnvGate.new) }.play;

+


+


+

x.release

+


+

(

+

y.free;

+

~bus.free;

+

)

+


+


+

Ex.2f) Conditional feedback

+

+

// defining the next sample depending on some characteristics of the previous one(s)

+

// This can be done with the if UGen and Select.

+

// 'if' doesn't support multichannel expansion, so take Select here

+


+

s.scope

+


+

// noisy texture with beeps

+


+

(

+

x = {

+

var src = LFDNoise3.ar(1, 0.1);

+

// ar modulators to be passed (avoid annoying steady tone caused by kr)

+

var mod1 = LFDNoise3.ar(1).range(0.01, 0.2);

+


+

// already slight difference results in quite strong stereo decorrelation

+

var mod2 = LFDNoise3.ar(1).range([0.0001, 0.0002],  0.0049);

+


+

Fb1({ |in, out|

+

// give same names as above for better readability

+

var src = in[0][0];

+

var mod1 = in[0][1];

+

var mod2 = in[0][2];

+

softclip(

+

Select.kr(

+

// as mod2 is stereo we get stereo expansion

+

// and in turn different selections

+

+

// outDepth = [[1, 6]]

+

// so out[0] refers to out[i-1], out[1] to out[i-6]

+

+

out[0] % 0.005 < mod2,

+

[out[1].neg * mod1, out[0] * 0.1]

+

) + src + out[0]

+

)

+

// lopass filtering with lag

+

}, [src, mod1, mod2], 2, 1, [[1, 6]]).lag(0.001) * 0.5

+

}.play

+

)

+


+

x.release

+


+


+


+

Examples 3) Conventions and args

+


+

Ex.3a) Multichannel feedback / feedforward

+


+

// in and out can be multichannel signals of arbitrary size or collections thereof,

+

// however arbitrary nesting is not supported,

+

// outSize arg has to be passed explicitely,

+

// size of in arg is taken over automatically.

+


+
// also mind the difference between size 0 and 1:

+

// with outSize of 1 or [0] Fb1 returns an array 

+


+

// here out is of size 3, in of sizes [3, 0]

+


+

(

+

x = {

+

var inSig = SinOsc.ar(LFDNoise3.ar(0.01 ! 3).range(100, 101)); // 3 channel in signal

+

var lfo = LFDNoise3.ar(0.1).linexp(-1, 1, 0.2, 10);

+

var sig;

+

sig = LPF.ar(

+

Fb1({ |in, out|

+

// in[0][0] and in[1][0] represent current and previous 3 channel samples from inSig

+

// in[0][1] represents current sample from lfo

+

// rotate causes cross-feedback of 3 channels

+

// with reverse only first and last would cross

+

(in[1][0] * in[0][1] / max(0.001, (in[1][0] - out[1].rotate(1)).abs)).tanh

+

// outSize 3 has to be passed

+

}, [inSig, lfo], 3, [2, 1], 2

+

), 15000) * 0.1;

+

Splay.ar(sig)

+

}.play

+

)

+


+

x.release

+


+


+

// again out is of size 3, in of sizes [3, 3]

+


+

(

+

x = {

+

var inSig = SinOsc.ar(LFDNoise3.ar(0.01 ! 3).range(100, 101)); // 3 channel in signal

+

var mod = SinOsc.ar([1, 2.001, 3.999] * 120).linexp(-1, 1, 0.2, 10);

+

var sig;

+

sig = LPF.ar(

+

Fb1({ |in, out|

+

// in[0][0] and in[1][0] represent current and previous 3 channel samples from inSig

+

// in[0][1] represents current 3 samples from mod

+

// rotate causes cross-feedback of 3 channels

+

// with reverse only first and last would cross

+

(in[1][0] * in[0][1] / max(0.001, (in[1][0] - out[1].rotate(1)).abs)).tanh

+

// outSize has to be passed

+

}, [inSig, mod], 3, [2, 1], 2

+

), 15000) * 0.05;

+

Splay.ar(sig)

+

}.play

+

)

+


+

x.release

+


+


+

// it's also possible to let func return an array of (multichannel) signals,

+

// outSize must be set accordingly, here [2, 0],

+

// whereby the mono within the array is a "helper feedback"

+


+

(

+

x = {

+

var inSig = SinOsc.ar(LFDNoise3.ar(1.5 ! 2).exprange(50, 100));

+

var lfo = LFDNoise3.ar(5).linexp(-1, 1, 0.5, 100);

+

var sig;

+

sig = LPF.ar(

+

Fb1({ |in, out|

+

// in[1][0] represents previous 2 channel samples from inSig

+

// in[0][1] represents current sample from lfo

+

+

// reverse causes cross-feedback of 2 main channels

+

// main feedback crosses with helper feedback

+

[

+

// for main feedback use helper feedback 

+

(out[1][1] / max(0.001, (in[1][0] - out[1][0].reverse).abs)).tanh,

+

// for helper feedback use first channel of main feedback

+

(out[1][0][0] + 0.1 / max(0.01, ((in[0][1].abs)))).tanh

+

]

+

// outSize [2, 0] has to be passed

+

}, [inSig, lfo], [2, 0], [2, 1], 2

+

), 12000) * 0.2;

+

// return main feedback

+

sig[0]

+

}.play

+

)

+


+

x.release

+


+


+


+

// here 2 x stereo, outSize == [2, 2]

+


+

(

+

x = {

+

// two stereo sources

+

var in_1 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(100, 101));

+

var in_2 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(150, 151));

+

var lfo = LFDNoise3.ar(0.1).linexp(-1, 1, 0.2, 10);

+

var sig;

+

sig = LPF.ar(

+

Fb1({ |in, out|

+

// rename for better readability

+


+

// previous ins are stereo

+

var prevIn_1 = in[1][0];

+

var prevIn_2 = in[1][1];

+


+

// mono lfo

+

var lfo = in[0][2];

+


+

// out is 2 x 2 (see below)

+

var prevOut_1 = out[1][0]; // stereo

+

var prevOut_2 = out[1][1]; // stereo

+


+

// we return an array of two stereo signals

+

[

+

(prevIn_1 * lfo / max(0.001, (prevIn_1 - prevOut_1.reverse).abs)),

+

(prevIn_2 * lfo / max(0.001, (prevIn_2 - prevOut_2.reverse).abs))

+

].tanh

+


+

// outSize [2, 2] has to be passed

+

}, [in_1, in_2, lfo], [2, 2], 2, 2

+

), 15000) * 0.05;

+

sig[0] + sig[1]; // mix together

+

// sig[0];

+

// sig[1];

+

}.play

+

)

+


+

x.release

+


+


+

// variant: cross feedback within first stereo out (a) plus

+

// cross feedback the stereo signals with each other (b)

+


+

// at the end take only first stereo out

+

// because of (b) the 150 Hz of in_2 are contained in the resulting signal

+


+

(

+

x = {

+

var in_1 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(100, 101));

+

var in_2 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(150, 151));

+

var lfo = LFDNoise3.ar(0.1).linexp(-1, 1, 0.2, 10);

+

var sig;

+

sig = LPF.ar(

+

Fb1({ |in, out|

+

// rename for better readability

+


+

// previous ins are stereo

+

var prevIn_1 = in[1][0];

+

var prevIn_2 = in[1][1];

+


+

// mono lfo

+

var lfo = in[0][2];

+


+

// out is 2 x 2 (see below)

+

var prevOut_1 = out[1][0]; // stereo

+

var prevOut_2 = out[1][1]; // stereo

+


+

// we return an array of two stereo signals

+


+

[

+

(prevIn_1 * lfo / max(0.001, (prevIn_1 - prevOut_2.reverse).abs)),

+

(prevIn_2 * lfo / max(0.001, (prevIn_2 - prevOut_1).abs))

+

].tanh

+


+

// outSize has to be passed

+

}, [in_1, in_2, lfo], [2, 2], 2, 2

+

), 15000) * 0.05;

+

sig[0]

+

}.play

+

)

+


+

x.release

+


+


+


+

Ex.3b) inInit / outInit

+


+


+

// linear congruential generator

+


+

// this is not a strict linear congruential generator

+

// as the server doesn't know integers, it's done with floats,

+

// all is blurred by floating point inaccuracy

+

// however interesting results can be obtained

+


+

// different start values can produce different orbits

+


+

// WARNING: can produce loud high pitches with certain init values and factors

+

// as a result of short iteration cycles, take LPF !

+


+


+

// same init value for both channels

+


+

(

+

x = {

+

var sig = Fb1({ |in, out|

+

out[1] * 5.239 % 1

+

},

+

outSize: 2,

+

outInit: 1 // [1] is equivalent

+

).tanh * 0.2;

+

LPF.ar(sig, 2000)

+

}.play

+

)

+


+

x.release

+


+


+

// other iteration sequence by different init value

+


+

(

+

x = {

+

var sig = Fb1({ |in, out|

+

out[1] * 5.239 % 1

+

},

+

outSize: 2,

+

outInit: 2

+

).tanh * 0.2;

+

LPF.ar(sig, 2000)

+

}.play

+

)

+


+

x.release

+


+


+

// defining different init values per channel

+


+

(

+

x = {

+

var sig = Fb1({ |in, out|

+

out[1] * 5.239 % 1

+

},

+

outSize: 2,

+

outInit: [1, 2]

+

).tanh * 0.2;

+

LPF.ar(sig, 2000)

+

}.play

+

)

+


+

x.release

+


+


+

// mono, two init values for one channel (previous and previous of previous)

+

// this needs double brackets for outInit

+


+

(

+

x = {

+

var sig = Fb1({ |in, out|

+

out[1] * 2 + (out[2] * 3) % 1.01

+

},

+

outSize: 1,

+

outInit: [[2, 6]], 

+

outDepth: 3 // needed as we look back for 2 values

+

).tanh * 0.2;

+

LPF.ar(sig, 2000)

+

}.play

+

)

+


+

x.release

+


+


+

// stereo, different arrays of init values per channel

+


+

(

+

x = {

+

var sig = Fb1({ |in, out|

+

out[1] * 2 + (out[2] * 3) % 1.01

+

},

+

outSize: 2,

+

outInit: [[3, 1], [2, 5]], 

+

outDepth: 3 

+

).tanh * 0.2;

+

LPF.ar(sig, 2000)

+

}.play

+

)

+


+

x.release

+


+


+

// inInit values can be defined in the same way as outInit

+


+

// want a trigger at start in connection with Dust

+


+

(

+

x = {

+

var trig = Dust.ar(0.3);

+

var src = SinOsc.ar(1000);

+

var sig = Fb1({ |in, out|

+

var tr = in[1][0];

+

var mod = in[0][1];

+

(out[1] + tr * (mod * 0.02 + 0.999999))

+

},

+

in: [trig, src],

+

inDepth: 2,

+

// here both in buffers get init values, only the first is relevant

+

inInit: 1,  // [1, 0] doesn't make a difference 

+

).lag(0.005).tanh * 0.5;

+

sig

+

}.play

+

)

+


+

x.release

+


+

// inInit and outInit cannot be differentiated for a multichannel component of a multichannel in / out.

+

// If you want to do such, you'd have to split the inner 

+

// multichannel component and differentiate the outer one. 

+


+


+

Ex.3c) inDepth / outDepth

+


+

// Normally, and like in most previous examples,

+

// out[j] and in[j] in func refer to samples out[i-j] and in[i-j],

+

// in[0] to the current input samples.

+

// The lookback size can be determined by passing Integers to inDepth / outDepth, e.g.

+

// with inDepth = 2 you can refer to in[0] and in[i-1]

+

// with outDepth = 3 you can refer to out[i-1] and out[i-2], 

+

// out[0] refers to out[i-blockSize].

+


+

// When refering not to previous but to earlier samples,

+

// passing specified inDepth / outDepth indices is saving UGens.

+


+


+

// Here in[0] refers to in[0], the current sample(s), and

+

// in[1] refers to in[i-56].

+


+

(

+

x = {

+

var src = SinOsc.ar(500 * LFDNoise3.ar(5));

+

var sig = Fb1({ |in, out|

+

(out[1] / max(0.01, (in[1] - in[0]))).tanh

+

},

+

in: src,

+

inDepth: [[0, 56]],

+

outInit: 1

+

) ! 2 * 0.1 ;

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

// looking back less far changes the sound colour

+


+

(

+

x = {

+

var src = SinOsc.ar(500 * LFDNoise3.ar(5));

+

var sig = Fb1({ |in, out|

+

(out[1] / max(0.01, (in[1] - in[0]))).tanh

+

},

+

in: src,

+

inDepth: [[0, 29]],

+

outInit: 1

+

) ! 2 * 0.1;

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

// differentiate inDepth per channel

+


+

(

+

x = {

+

// stereo in

+

var src = SinOsc.ar(500 * LFDNoise3.ar(5!2));

+

var sig = Fb1({ |in, out|

+

(out[1] / max(0.01, (in[1] - in[0]))).tanh

+

},

+

outSize: 2,

+

in: src,

+

inDepth: [[0, 29], [0, 56]],

+

outInit: 1

+

) * [0.2, 0.1];

+

sig

+

}.play

+

)

+


+

x.release

+


+

// inDepth and outDepth cannot be differentiated for a multichannel component of a multichannel in / out.

+

// If you want to do such, you'd have to split the inner 

+

// multichannel component and differentiate the outer one. 

+


+


+

Ex.3d) blockSize / blockFactor

+


+

// Normally Fb1's blockSize should equal the server's current blockSize,

+

// which can be set as a server option, per default it's 64.

+


+

// If you are using a different blockSize, you can either 

+

// reset it for the examples in this helpfile ...

+


+

(

+

if (s.options.blockSize != 64) {

+

s.options.blockSize = 64;

+

s.quit.reboot;

+

}

+

)

+


+

// ... or run the examples with passing a different blockSize, e.g. with: 

+


+

Fb1(..., blockSize: s.options.blockSize)

+


+


+

// You can however try to creativily use a "wrong" blockSize and play with artefacts, 

+

// variant of Ex. 3c 

+


+

(

+

x = {

+

// stereo in

+

var src = SinOsc.ar(300 * LFDNoise3.ar(1!2));

+

var sig = Fb1({ |in, out|

+

(out[1] / max(0.01, (in[1] - in[0]))).tanh

+

},

+

outSize: 2,

+

in: src,

+

inDepth: [[0, 15], [0, 19]],

+

outInit: 1,

+

blockSize: 33

+

) * 0.2;

+

LPF.ar(sig, 3000)

+

}.play

+

)

+


+

x.release

+


+

// variant of Ex. 3c

+

// suppose a blockSize of 64, to look back to in[i-150] set blockFactor to 3.

+


+

(

+

x = {

+

// stereo in

+

var src = SinOsc.ar(500 * LFDNoise3.ar([0.3, 7]));

+

var sig = Fb1({ |in, out|

+

(out[1] / max(0.001, (in[1] - in[0]))).distort

+

},

+

outSize: 2,

+

in: src,

+

inDepth: [[0, 150], [0, 29]],

+

outInit: 1,

+

blockFactor: 3

+

) * [0.07, 0.15];

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

Ex.3e) func index

+


+

// func can take an index as third arg, it runs from 0 to blockSize - 1

+

// this can be used to define the feedback relation depending on it

+


+

// note that inDepth is set to [2, 1] as we look back to inSig[i-1] (in[1][0]),

+

// but not to lfo[i-1] (in[0][1] == lfo[0]), this saves 128 UGens !

+


+


+

(

+

x = {

+

var inSig = SinOsc.ar([50, 50.1]);

+

var lfo = SinOsc.ar(LFDNoise3.ar(0.1).range(0, 500)).range(0, [100, 105]);

+

LPF.ar(

+

Fb1({ |in, out, i|

+

(

+

// establish alternating feedback relations in the synthdef graph

+

i.odd.if {

+

in[0][0] * in[0][1] + out[1] 

+

}{

+

(in[0][0] - in[1][0]) * out[1]

+

}

+

).tanh

+

}, [inSig, lfo], 2, [2, 1], 2

+

) * 0.1, 12000)

+

}.play

+

)

+


+

x.release

+


+


+

Ex.4) Saving CPU

+


+

// UGens written in func are generated as often as blockSize.

+

// Therefore, if possible, references to kr UGens outside save resources.

+

// In addition look for hidden unnecessary operations, which can add hundreds of UGens

+


+


+

// 2440 UGens (with blockSize == 64)

+

// deliberately bad, deterministic lfo is generated blockSize times

+


+


+

(

+

x = {

+

var sig, src;

+

src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25);

+

sig = Fb1({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

var lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

softclip((a * a * a) + (a * a) + a + (a * a * b)  / max(lfo, a + b));

+

}, src, 2) * 0.1;

+

LPF.ar(sig, 3000)

+

}.play

+

)

+


+

x.release

+


+


+


+

// 2188 UGens as (blockSize - 1) * 4 = 63 * 4 = 252 UGens are saved

+


+


+

(

+

x = {

+

var sig, src, lfo;

+

src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25);

+

lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

sig = Fb1({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

softclip((a * a * a) + (a * a) + a + (a * a * b)  / max(lfo, a + b));

+

}, src, 2) * 0.1;

+

LPF.ar(sig, 3000)

+

}.play

+

)

+


+

x.release

+


+


+


+

// still bad though when looking at the the algebraic identity

+

// a^3 + a^2 + a + (a * a * b) = ((a + b) * a + a) * a + a

+

// these are 8 vs 5 operations, so with stereo we can save further 

+

// ((8 - 5) * 2) * 64 = 384 UGens

+


+


+

// 1804 UGens

+


+

(

+

x = {

+

var sig, src, lfo;

+

src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25);

+

lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

sig = Fb1({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

// with SC's L/R-precendence we can write without brackets

+

softclip(a + b * a + a * a + a / max(lfo, a + b));

+

}, src, 2) * 0.1;

+

LPF.ar(sig, 3000)

+

}.play

+

)

+


+

x.release

+


+


+

// without forcing the topological order of BufRds and BufWrs further UGens are saved,

+

// this might or might not be the same result, might be distorted in worst case,

+

// however in all my tests I didn't encounter a single example where it was different

+


+

// 1713 UGens

+


+


+

(

+

x = {

+

var sig, src, lfo;

+

src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25);

+

lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

sig = Fb1({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

// with SC's L/R-precendence we can write without brackets

+

softclip(a + b * a + a * a + a / max(lfo, a + b));

+

}, src, 2, graphOrderType: 0) * 0.1;

+

LPF.ar(sig, 3000)

+

}.play

+

)

+


+

x.release

+


+


+

// check if it's the same - run silently

+


+

(

+

x = {

+

var sig, src, lfo;

+

src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25);

+

lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

sig = Fb1({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

// with SC's L/R-precendence we can write without brackets

+

softclip(a + b * a + a * a + a / max(lfo, a + b));

+

}, src, 2, graphOrderType: 0) -

+

Fb1({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

softclip(a + b * a + a * a + a / max(lfo, a + b));

+

}, src, 2) * 0.1;

+

LPF.ar(sig, 3000)

+

}.play

+

)

+


+

x.release

+


+


+

// see also Ex.5 for saving CPU with kr

+


+


+


+

Ex.5) Control rate

+


+


+

// Ex.4 with kr and K2A

+


+

(

+

x = {

+

var sig, src, lfo;

+

src = SinOsc.kr(90 * LFDNoise3.kr(0.3!2).range(0.98, 1.02)) * SinOsc.kr(45.25);

+

lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

sig = Fb1.kr({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

// with SC's L/R-precendence we can write without brackets

+

softclip(a + b * a + a * a + a / max(lfo, a + b));

+

}, src, 2, graphOrderType: 0) * 0.1;

+

LPF.ar(K2A.ar(sig), 3000)

+

}.play

+

)

+


+

x.release

+


+


+

// FM with same signal

+


+

(

+

x = {

+

var sig, src, lfo;

+

src = SinOsc.kr(90 * LFDNoise3.kr(0.3!2).range(0.98, 1.02)) * SinOsc.kr(45.25);

+

lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01);

+

sig = Fb1.kr({ |in, out|

+

var a = in[0];

+

var b = out[1];

+

// with SC's L/R-precendence we can write without brackets

+

softclip(a + b * a + a * a + a / max(lfo, a + b));

+

}, src, 2, graphOrderType: 0) * 0.1;

+

SinOsc.ar(2000 * sig, 0, 0.1) 

+

}.play

+

)

+


+

x.release

+


+


+


+


+ + diff --git a/Help/Fb1_Duffing.html b/Help/Fb1_Duffing.html new file mode 100755 index 0000000..4614781 --- /dev/null +++ b/Help/Fb1_Duffing.html @@ -0,0 +1,324 @@ + + + + + + + + + + + +

Fb1_Duffing Duffing pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+

+

Fb1_ODE wrapper for the Duffing ODE system with external f:

+


+

y'(t) = w(t)

+

w'(t) =  f(t) + (gamma * cos(omega * t)) - (delta * w(t)) - (beta * y(t)^3) - (alpha * y(t)) 

+


+

coming from the 2nd order equation

+


+

y''(t) + (delta * y'(t)) + (alpha * y(t)) + (beta * y(t)^3) =  (gamma * cos(omega * t)) + f(t)

+


+

It returns a 2-channel signal. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [2], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [3]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (f = 0, alpha = 0, beta = 1, gamma = 1, delta = 1, omega = 1, tMul = 1, t0 = 0, y0 = #[1, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_Duffing ar object.

+

+

f - Defaults to 0.

+

alpha - Defaults to 0.

+

beta - Defaults to 1.

+

gamma - Defaults to 1.

+

delta - Defaults to 1.

+

omega - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[1, 0].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, alpha = 0, beta = 1, gamma = 1, delta = 1, omega = 1, tMul = 1, t0 = 0, y0 = #[1, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, alpha = 0, beta = 1, gamma = 1, delta = 1, omega = 1, tMul = 1, t0 = 0, y0 = #[1, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_Duffing kr object.

+

+

f - Defaults to 0.

+

alpha - Defaults to 0.

+

beta - Defaults to 1.

+

gamma - Defaults to 1.

+

delta - Defaults to 1.

+

omega - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[1, 0].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\Duffing, { |t, y, f = 0, alpha = 0, beta = 1, gamma = 1, delta = 1,

+

omega = 1|

+

[

+

{ y[1] },

+

{ gamma * cos(omega * t) + f - (delta * y[1]) -

+

((beta * y[0] * y[0] - alpha) * y[0]) }

+

]

+

}, 0, [1, 0], 1, 1);

+


+


+


+

// steady external force, play alpha and beta

+


+

(

+

x = {

+

var sig = Fb1_Duffing.ar(

+

0.7, MouseX.kr(1, 3), MouseY.kr(1, 3), 2, 0, 0.8, tMul: 650);

+

Limiter.ar(sig[0..1], 0.3) * EnvGen.ar(Env.asr(0.1, curve: 3))

+

}.play

+

)

+


+

x.release

+


+


+

// oscillating force, modulate tMul

+


+

(

+

x = {

+

var sig = Fb1_Duffing.ar(

+

SinOsc.ar(3).range(1, 5), 1, 1, 2, 0, 0.8,

+

tMul: LFDNoise0.kr(1).range(700, 2000).lag(0.2)

+

);

+

Limiter.ar(sig[0..1], 0.2) * EnvGen.ar(Env.asr(0.1, curve: 3))

+

}.play

+

)

+


+

x.release

+


+


+


+


+


+ + diff --git a/Help/Fb1_Hopf.html b/Help/Fb1_Hopf.html new file mode 100755 index 0000000..a8f1ec4 --- /dev/null +++ b/Help/Fb1_Hopf.html @@ -0,0 +1,359 @@ + + + + + + + + + + + +

Fb1_Hopf Hopf pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Fb1_ODE wrapper for the Hopf ODE system with external f:

+


+

v'(t) = (mu - (v(t)^2 + w(t)^2)) * v(t) - (theta * w(t)) + f(t)

+

w'(t) = (mu - (v(t)^2 + w(t)^2)) * w(t) + (theta * v(t)) 

+


+

It returns a 2-channel signal. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [4], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [5]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. 

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): 

+

"Adaptive Frequency Oscillators and Applications". 

+

The Open Cybernetics and Systemics Journal, 3, 64-69.

+

https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access

+

Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html/

+

[2] Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): 

+

"Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". 

+

Frontiers in Neurorobotics. Published online 2017 Mar 21

+

https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full

+

[3] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[4] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[5] https://git.iem.at/davidpirro/henri

+

+


+

Creation / Class Methods

+


+

*new (f = 0, mu = 1, theta = 1, tMul = 1, t0 = 0, y0 = #[1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_Hopf ar object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

theta - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, mu = 1, theta = 1, tMul = 1, t0 = 0, y0 = #[1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, mu = 1, theta = 1, tMul = 1, t0 = 0, y0 = #[1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_Hopf kr object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

theta - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\Hopf, { |t, y, f = 0, mu = 1, theta = 1|

+

var u, v;

+

u = y[0] * y[0] + (y[1] * y[1]);

+

v = mu - u;

+

[

+

{ v * y[0] - (theta * y[1]) + f },

+

{ v * y[1] + (theta * y[0]) },

+

]

+

}, 0, [1, 1], 0.3, 0.3);  // scaling as standard params lead to high level output

+


+


+


+

// change param mu and static external force (f = mu = 0: harmonic oscillation)

+


+

x = { Fb1_Hopf(MouseX.kr(0, 1).poll, MouseY.kr(1.5, 5).poll, 1, 200 * 2pi) * 0.2 }.play

+


+

x.release

+


+


+

// f fed with a SinOsc with frequency coupled to tMul by an integer factor,

+

// mu movement can tilt over the waveform

+


+

(

+

SynthDef(\hopf, { |out, freqFactor = 1,

+

srcAmp = 1, mu = 1, theta = 1, tMul = 1, amp = 0.05|

+

var sig;

+

sig = Fb1_Hopf.ar(

+

SinOsc.ar(tMul / freqFactor) * srcAmp,

+

mu.lag(1), theta, tMul

+

);

+

Out.ar(out, Limiter.ar(sig[0..1]) * amp.lag(1))

+

}, metadata: (

+

specs: (

+

freqFactor: [5, 30, \lin, 1, 18],

+

srcAmp: [5, 100, \lin, 0, 27],

+

mu: [0, 50, \lin, 0, 25],

+

theta: [0.1, 7, \lin, 0, 3.8],

+

tMul: [200, 1000, \lin, 0, 450],

+

amp: [0.01, 0.07, \db, 0, 0.05]

+

)

+

)).add;

+


+

\hopf.sVarGui.gui

+

)

+


+


+

// focussing on the tilt effect:

+

// LFO crossing a critical boundary of Hopf's mu parameter

+


+

(

+

x = {

+

var freq = LFDNoise3.kr(0.2).exprange(200, 700), sig;

+

sig = Fb1_Hopf.ar(

+

f: SinOsc.ar(freq) * 30,

+

mu: SinOsc.ar(SinOsc.ar(0.1, -pi/2).exprange(0.2, 20), -pi/2).range(5, 30).poll,

+

theta: 1,

+

tMul: freq

+

);

+

Limiter.ar(sig[0..1]) * 0.1 * EnvGen.ar(Env.asr(0.1, curve: 3))

+

}.play

+

)

+


+

x.release

+


+ + diff --git a/Help/Fb1_HopfA.html b/Help/Fb1_HopfA.html new file mode 100755 index 0000000..07f256a --- /dev/null +++ b/Help/Fb1_HopfA.html @@ -0,0 +1,366 @@ + + + + + + + + + + + +

Fb1_Hopf A Adaptive Hopf pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

This is an adaptive variant of Hopf, i.e. it can hold the frequency of an oscillating input f after it vanishes. The model refers to [1], see also [2] (4.1.) for an enhancement implemented with Fb1_HopfAFDC. The parameter naming follows the convention of [2].

+


+

v'(t) = (mu - (v(t)^2 + w(t)^2)) * v(t) - (theta(t) * w(t)) + f(t)

+

w'(t) = (mu - (v(t)^2 + w(t)^2)) * w(t) + (theta(t) * v(t)) 

+

theta'(t) = -eta * f(t) * w(t) / sqrt(v(t)^2 + w(t)^2)

+


+

It returns a 3-channel signal. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [4], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [5]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): 

+

"Adaptive Frequency Oscillators and Applications". 

+

The Open Cybernetics and Systemics Journal, 3, 64-69.

+

https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access

+

Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html/

+

[2] Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): 

+

"Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". 

+

Frontiers in Neurorobotics. Published online 2017 Mar 21

+

https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full

+

[3] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[4] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[5] https://git.iem.at/davidpirro/henri

+

+


+

Creation / Class Methods

+


+

*new (f = 0, mu = 0, eta = 1, tMul = 1, t0 = 0, y0 = #[1, 1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_HopfA ar object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

eta - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 3.

+

Defaults to #[1, 1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, mu = 1, eta = 1, tMul = 1, t0 = 0, y0 = #[1, 1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, mu = 1, eta = 1, tMul = 1, t0 = 0, y0 = #[1, 1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_HopfA kr object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

eta - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 3.

+

Defaults to #[1, 1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\HopfA, { |t, y, f = 0, mu = 1, eta = 1|

+

var u, v;

+

u = y[0] * y[0] + (y[1] * y[1]);

+

v = mu - u;

+

[

+

{ v * y[0] - (y[2] * y[1]) + f },

+

{ v * y[1] + (y[2] * y[0]) },

+

{ f.neg * y[1] * eta / sqrt(u) }

+

]

+

}, 0, [1, 1, 1], 0.3, 0.3);  // scaling as standard params lead to high level output

+


+


+


+

// reasonable adaption with sine source

+

// mouse left turns source down, but oscillator still keeps frequency

+

// move mouse to right to turn source on again

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(3), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf)

+

).midiratio;

+

var hold = (MouseX.kr(0, 1) > 0.1).poll;

+

var src = SinOsc.ar(ratio * 200);

+

var sig = Fb1_HopfA.ar(src * hold.lag(0.5), 0.15, 2, 800);

+

sig[0] ! 2 * 0.5

+

}.play

+

)

+


+

x.release

+


+


+

// with Saw the result is less exact, sometimes Hopf jumps to higher partials

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(3), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf)

+

).midiratio;

+

var hold = (MouseX.kr(0, 1) > 0.1).poll;

+

var src = Saw.ar(ratio * 200);

+

var sig = Fb1_HopfA.ar(src * hold.lag(0.5), 0.15, 2, 800);

+

sig[0] ! 2 * 0.5

+

}.play

+

)

+


+

x.release

+


+


+

// an inexact adaption can be used though to generate interesting irregular variations

+

// listen for a while

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(3), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf)

+

).midiratio;

+

var src = Saw.ar(ratio * 200, 0.3);

+

var sig = Fb1_HopfA.ar(src, 8, 10.5, 600);

+

sig[0] ! 2 * 0.3

+

}.play

+

)

+


+

x.release

+


+


+ + diff --git a/Help/Fb1_HopfAFDC.html b/Help/Fb1_HopfAFDC.html new file mode 100755 index 0000000..4c4ef30 --- /dev/null +++ b/Help/Fb1_HopfAFDC.html @@ -0,0 +1,406 @@ + + + + + + + + + + + +

Fb1_Hopf AFDC Adaptive Hopf pseudo ugen with fast dynamical coupling

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

This is an adaptive variant of Hopf, which enhances the adaption mechanism of [1], see [2] (4.1.) for a description. The parameter naming follows the convention of [2].

+


+

v'(t) = (mu - (v(t)^2 + w(t)^2)) * v(t) - (theta(t) * w(t)) + p(t)

+

w'(t) = (mu - (v(t)^2 + w(t)^2)) * w(t) + (theta(t) * v(t)) 

+

tau * beta'(t) = beta0 - beta(t) + (kappa * p(t) * v(t))

+

tau * epsilon'(t) = epsilon0 - epsilon(t) + (kappa * f(t) * p(t))

+

theta'(t) = -eta * p(t) * w(t) / sqrt(v(t)^2 + w(t)^2)

+


+

with 

+


+

p(t) = (epsilon(t) * f(t)) - (beta(t) * v(t))

+


+

It returns a 5-channel signal. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [4], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [5]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): 

+

"Adaptive Frequency Oscillators and Applications". 

+

The Open Cybernetics and Systemics Journal, 3, 64-69.

+

https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access

+

Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html/

+

[2] Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): 

+

"Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". 

+

Frontiers in Neurorobotics. Published online 2017 Mar 21

+

https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full

+

[3] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[4] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[5] https://git.iem.at/davidpirro/henri

+

+


+

Creation / Class Methods

+


+

*new (f = 0, mu = 1, eta = 1, tau = 1, kappa = 1, tMul = 1, t0 = 0, y0 = #[1, 1, 0.01, 0.01, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_HopfAFDC ar object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

eta - Defaults to 1.

+

tau - Defaults to 1.

+

kappa - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 5.

+

Defaults to #[1, 1, 0.01, 0.01, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, mu = 1, eta = 1, tau = 1, kappa = 1, tMul = 1, t0 = 0, y0 = #[1, 1, 0.01, 0.01, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, mu = 1, eta = 1, tau = 1, kappa = 1, tMul = 1, t0 = 0, y0 = #[1, 1, 0.01, 0.01, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_HopfAFDC kr object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

eta - Defaults to 1.

+

tau - Defaults to 1.

+

kappa - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 5.

+

Defaults to #[1, 1, 0.01, 0.01, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+

// beta0 and epsilon0 are taken over as components of indices 2 and 3 from y0

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\HopfAFDC, { |t, y, f = 0, mu = 1,

+

eta = 1, tau = 1, kappa = 1, beta0 = 0.01, epsilon0 = 0.01|

+

var p, u, v;

+

u = y[0] * y[0] + (y[1] * y[1]);

+

v = mu - u;

+

p = y[3] * f - (y[2] * y[0]);

+

[

+

{ v * y[0] - (y[4] * y[1]) + p },

+

{ v * y[1] + (y[4] * y[0]) },

+

{ beta0 - y[2] + (kappa * p * y[0]) / tau },

+

{ epsilon0 - y[3] + (kappa * p * f) / tau },

+

{ p.neg * y[1] * eta / sqrt(u) }

+

]

+

}, 0, [1, 1, 0.01, 0.01, 1], 0.3, 0.3);

+


+


+


+

// adaption to sine source (R) by Fb1_HopfAFDC (L)

+

// mouse left turns source down for the Hopf

+

// for comparison the source continues in the right channel

+

// move mouse to right to turn source on again

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(3), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf)

+

).midiratio;

+

var hold = (MouseX.kr(0, 1) > 0.1).poll;

+

var src = SinOsc.ar(ratio * 200);

+

var sig = Fb1_HopfAFDC.ar(src * hold.lag(0.1), 0.2, 0.6, 1, 50, 150) *

+

EnvGen.ar(Env.asr(0.05));

+

[sig[0] * 0.7, src * 0.1]

+

}.play

+

)

+


+

x.release

+


+


+

// in contrast to Fb1_HopfA adaption to the Saw works quite well

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(3), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf)

+

).midiratio;

+

var hold = (MouseX.kr(0, 1) > 0.1).poll;

+

var src = Saw.ar(ratio * 200);

+

var sig = Fb1_HopfAFDC.ar(src * hold.lag(0.1), 0.2, 0.6, 1, 50, 150) *

+

EnvGen.ar(Env.asr(0.05));

+

[sig[0] * 0.5, src * 0.04]

+

}.play

+

)

+


+

x.release

+


+


+

// it works still with faster tempo and bigger jumps

+

// however big jumps and/or the hold gate make the system instable,

+

// compose with clip helps

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(7), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf) + Drand([0, 12, 24], inf)

+

).midiratio;

+

var hold = MouseX.kr(0, 1) > 0.1;

+

var src = Saw.ar(ratio * 200);

+

var tMul = 150;

+

var sig = Fb1_HopfAFDC.ar(src * hold.lag(0.1), 0.2, 0.6, 1, 50, tMul,

+

compose: { |x| x.clip2(100) }

+

) * EnvGen.ar(Env.asr(0.05));

+

[sig[0] * 0.5, src * 0.04]

+

}.play

+

)

+


+

x.release

+


+


+

// confused adaption by feeding with phase modulated signal

+


+

(

+

x = {

+

var ratio = Demand.ar(

+

Impulse.ar(3), 0,

+

Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf)

+

).midiratio;

+

var src = SinOsc.ar(ratio * 200, SinOsc.ar(200).range(0.2, 1));

+

var sig = Fb1_HopfAFDC.ar(src, 1.5, 1, 1, 100, 200) *

+

EnvGen.ar(Env.asr(0.05));

+

sig[0] ! 2 * 0.3

+

}.play

+

)

+


+

x.release

+


+ + diff --git a/Help/Fb1_Lorenz.html b/Help/Fb1_Lorenz.html new file mode 100755 index 0000000..80282e8 --- /dev/null +++ b/Help/Fb1_Lorenz.html @@ -0,0 +1,358 @@ + + + + + + + + + + + +

Fb1_Lorenz Lorenz pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Fb1_ODE wrapper for the Lorenz ODE system:

+


+

u'(t) = s * (v(t) - u(t))

+

v'(t) = (u(t) * (r - w(t))) - v(t)

+

w'(t) = (u(t) * v(t)) - (b * w(t))

+


+

It returns a 3-channel signal. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [4], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [5]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. 

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (s = 10, r = 30, b = 2, tMul = 1, t0 = 0, y0 = #[1, 1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_Lorenz ar object.

+

+

s - Defaults to 10.

+

r - Defaults to 30.

+

b - Defaults to 2.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 3.

+

Defaults to #[1, 1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (s = 10, r = 30, b = 2, tMul = 1, t0 = 0, y0 = #[1, 1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (s = 10, r = 30, b = 2, tMul = 1, t0 = 0, y0 = #[1, 1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_Lorenz kr object.

+

+

s - Defaults to 10.

+

r - Defaults to 30.

+

b - Defaults to 2.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 3.

+

Defaults to #[1, 1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\Lorenz, { |t, y, s = 10, r = 30, b = 2|

+

[

+

{ (y[1] - y[0]) * s },

+

{ (r - y[2]) * y[0] - y[1] },

+

{ (y[0] * y[1]) - (b * y[2]) }

+

]

+

}, 0, [1, 1, 1], 0.01, 0.01); // strong scaling as standard params lead to high level output

+


+


+

// Lorenz as controller 

+


+

(

+

x = {

+

var s = 10, r = 30, b = 3, tMul = MouseX.kr(0.1, 50), sig;

+

sig = Fb1_Lorenz.kr(s, r, b, tMul,

+

withScaling: false,

+

leakDC: false

+

).tanh.linlin(-1, 1, 100, LFDNoise3.kr(0.3).range(700, 1000));

+

SinOsc.ar(sig[0..1], 0, 0.2)

+

}.play;

+

)

+


+

x.release

+


+


+

// two channel audio with default params

+


+

x = { Fb1_Lorenz.ar(tMul: MouseX.kr(50, 300).poll)[0..1] }.play;

+


+

x.release

+


+


+

// with oscillating parameters the results can be quite diverse

+


+

(

+

x = {

+

var sig, s;

+

s = SinOsc.ar(200, 0, 15, 10);

+

sig = Fb1_Lorenz.ar(s, 22, 1, 170, y0: [1, 0, 0]);

+

Limiter.ar(sig[0..1]) * EnvGen.ar(Env.asr(0.1, curve: 3));

+

}.play

+

)

+


+

x.release

+


+


+

(

+

x = {

+

var sig, s;

+

s = SinOsc.ar(100, 0, 9, 10);

+

sig = Fb1_Lorenz.ar(s, 22, 1, 170, y0: [1, 0, 0]);

+

Limiter.ar(sig[0..1]) * EnvGen.ar(Env.asr(0.1, curve: 3));

+

}.play

+

)

+


+

x.release

+


+


+

(

+

x = {

+

var sig, s;

+

s = SinOsc.ar(100, 0, 10, 6);

+

sig = Fb1_Lorenz.ar(s, 20, 1.5, 170, y0: [1, 1, 0]);

+

Limiter.ar(sig[0..1]) * EnvGen.ar(Env.asr(0.1, curve: 3));

+

}.play

+

)

+


+

x.release

+


+


+ + diff --git a/Help/Fb1_MSD.html b/Help/Fb1_MSD.html new file mode 100755 index 0000000..c1b9413 --- /dev/null +++ b/Help/Fb1_MSD.html @@ -0,0 +1,324 @@ + + + + + + + + + + + +

Fb1_MSD mass spring damper model pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Fb1_ODE wrapper for the mass spring damper equation of motion:

+


+

y''(t) * mass = f(t) - (dampen * y'(t)) - (spring * y(t)) 

+


+

It returns a 2-channel signal with position and velocity. Fb1_SD with unified mass is slightly more efficient than Fb1_MSD and you can always rewrite. See Fb1_ODE help for general information about Fb1 ODE integrator UGens and further MSD examples.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [2], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [3]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (f = 0, mass = 1, spring = 1, dampen = 0, tMul = 1, t0 = 0, y0 = #[0, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_MSD ar object.

+

+

f - External force. Defaults to 0.

+

mass - Mass. Defaults to 1.

+

spring - Spring stiffness. Defaults to 1.

+

dampen - Dampening factor. Defaults to 0.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[0, 0].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, mass = 1, spring = 1, dampen = 0, tMul = 1, t0 = 0, y0 = #[0, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, mass = 1, spring = 1, dampen = 0, tMul = 1, t0 = 0, y0 = #[0, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_MSD kr object.

+

+

f - External force. Defaults to 0.

+

mass - Mass. Defaults to 1.

+

spring - Spring stiffness. Defaults to 1.

+

dampen - Dampening factor. Defaults to 0.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[0, 0].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\MSD, { |t, y, f = 0, mass = 1, spring = 1, dampen = 0|

+

[

+

{ y[1] },

+

{ f - (dampen * y[1]) - (spring * y[0]) / mass }

+

]

+

}, 0, [0, 0], 1, 1);

+


+


+


+

// 2nd channel (velocity) generates decaying sine wave

+

// (position does also, but is softer)

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 1500, dampen = 0.003,

+

sig = Fb1_MSD.ar(f, mass, spring, dampen);

+

sig[1] ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// oscillation as external force

+

// stays while spring oscillation decays

+


+

(

+

x = {

+

var f = SinOsc.ar(500, 0, 0.3), mass = 0.001, spring = 1500, dampen = 0.003,

+

sig = Fb1_MSD.ar(f, mass, spring, dampen);

+

sig[1] ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// MSD as modulator, kr saves ugens

+

// usable if, as here, it produces rather low frequencies

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 200, dampen = 0.003,

+

sig = Fb1_MSD.kr(f, mass, spring, dampen);

+

SinOsc.ar(sig[1].linlin(-1, 1, [100, 90], 700), 0, 0.2)

+

}.play

+

)

+


+

x.release

+


+ + diff --git a/Help/Fb1_ODE.html b/Help/Fb1_ODE.html new file mode 100755 index 0000000..e5ab963 --- /dev/null +++ b/Help/Fb1_ODE.html @@ -0,0 +1,1129 @@ + + + + + + + + + + + +

Fb1_ODE general ordinary differential equation integrator pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Pseudo ugen for integrating / audifying ordinary (systems of) differential equations with initial values in realtime, based on the Fb1 single sample feedback class. It makes use of Fb1_ODEdef and Fb1_ODEintdef, containers for ODEs and numerical solution methods, which provide an interface for adding new ODE systems or integration methods interactively. There exists a huge number of ODE models in different areas, e.g. have a look at the SIAM publication Exploring ODEs [1], it approaches the topic from an experimental point of view, which is quite related to the demands of practical audification / synthesis / processing. And of course it's fun to define your own ODEs, see this help file and Fb1_ODEdef.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [2], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [3]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: Fb1_ODE in its plain form (without tMul modulation, use of compose etc.) produces audio data as a numerical integration of an ODE initial value problem, defined by Fb1_ODEdef and a numerical procedure, defined by Fb1_ODEintdef. This of course supposes well-defined ODE systems and it should be kept in mind that the Fb1_ODE framework doesn't perform any mathematical checks regarding the principal existence and uniqueness of a solution of a given Fb1_ODEdef. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (name, argList, tMul = 1, t0, y0, intType = \sym2, compose, composeArIn, dt0, argList0, 

+

init_intType = \sym8, withOutScale = true, withDiffChannels = false, withTimeChannel = false, 

+

blockSize, graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_ODE ar object.

+

+

name - The name of the ODE defined and stored via Fb1_ODEdef. 

+

Can be one of the predefined ODEs, for which wrappers exist, or a self-defined one.

+

Expects a Symbol.

+

argList - The argList to be passed to the ODE. Can contain ar or kr UGens and

+

SequenceableCollections thereof.

+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

If no value is passed, the default value of the referred Fb1_ODEdef is taken, usually 0.

+

y0 - Initial value of the ODE. 

+

Expects number or array of correct size, which is determined by the Fb1_ODEdef.

+

If no value is passed, the default value of the referred Fb1_ODEdef is taken.

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE 

+

with a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (name, argList, tMul = 1, t0, y0, intType = \sym2, compose, composeArIn, dt0, argList0, 

+

init_intType = \sym8, withOutScale = true, withDiffChannels = false, withTimeChannel = false, 

+

blockSize, graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (name, argList, tMul = 1, t0, y0, intType = \sym4, compose, dt0, argList0, 

+

init_intType = \sym8, withOutScale = true, withDiffChannels = false, withTimeChannel = false, 

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_ODE kr object.

+

+

name - The name of the ODE defined and stored via Fb1_ODEdef. 

+

Can be one of the predefined ODEs, for which wrappers exist, or a self-defined one.

+

Expects a Symbol.

+

argList - The argList to be passed to the. Can contain kr UGens and

+

SequenceableCollections of thereof.

+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting usable oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

If no value is passed, the default value of the referred Fb1_ODEdef is taken, usually 0.

+

y0 - Initial value of the ODE. 

+

Expects number or array of correct size, which is determined by the Fb1_ODEdef.

+

If no value is passed, the default value of the referred Fb1_ODEdef is taken.

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples 1) Proof of concept

+


+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+


+

Ex.1a) The harmonic oscillator

+


+

// A sine/cos function is the solution of the second order differential equation

+


+

// y''(t) = -y(t)

+


+

// with the standard substitution ...

+


+

// w(t) = y'(t)

+


+

// ... this can be reformulated as a system of two equations of first order

+


+

// y'(t) = w(t)

+

// w'(t) = -y(t)

+


+

// In general an ODE can be written like this

+

// where Y and F are meant to be a vector-valued functions,

+

// F given and Y to be found

+


+

// Y'(t) = F(t, Y)

+


+


+

// For the corresponding Fb1_ODEdef the Function (F) must take time and - as here we have size 2 - 

+

// an array as arguments plus optional further arguments and 

+

// output an array of same size, which can be implemented by the evaluation of:

+


+

(

+

Fb1_ODEdef(\harmonic, { |t, y|

+

[y[1], y[0].neg]

+

}, 0, [0, 1], 1, 1); // default init values t0, y0 and scaling factors for output

+

)

+


+

// The stereo output is a pair of 90-degree-shifted sine waves.

+

// As one wave length would be 2pi seconds we multiply time by a factor 500 * 2pi to get 500 Hz.

+

// Changed blockSize is detected automatically.

+


+

x = { Fb1_ODE.ar(\harmonic, tMul: 500 * 2pi) * 0.1 }.play

+


+

x.release

+


+


+

// as with Fb1, method 'new' is equivalent to 'ar'

+


+

x = { Fb1_ODE(\harmonic, tMul: 500 * 2pi) * 0.1 }.play

+


+

x.release

+


+


+

// a default frequency could equivalently also be built into the model

+


+

(

+

Fb1_ODEdef(\harmonic_2, { |t, y|

+

[y[1], y[0].neg] * 500 * 2pi

+

}, 0, [0, 1], 1, 1); // default init values t0, y0 and scaling factors for output

+

)

+


+

x = { Fb1_ODE.ar(\harmonic_2) * 0.1 }.play

+


+

x.release

+


+


+


+

Ex.1b) Extending the harmonic oscillator to the mass-spring-damper model

+

+

// The mass-spring-damper model with externally applied force

+

// is described by the second order differential equation

+


+

// y''(t) * mass = f(t) - (dampen * y'(t)) - (spring * y(t))

+


+

// where dampen means the dampening factor and spring the spring stiffness.

+

// Again standard substitution 

+


+

// w(t) = y'(t)

+


+

// leads to the system of two first order equations

+


+

// y'(t) = w(t)

+

// w'(t) = (f(t) - (dampen * w(t)) - (spring * y(t))) / mass

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\MSD, { |t, y, f = 0, mass = 1, spring = 1, dampen = 0|

+

[

+

{ y[1] },

+

{ f - (dampen * y[1]) - (spring * y[0]) / mass }

+

]

+

}, 0, [0, 0], 1, 1);

+


+


+


+

// Here the resulting oscillation, which describes the position, is used for FM,

+

// the deflection converges to a value of 0.004, so take no LeakDC.

+


+

// LR difference results from slightly different linear mapping

+


+

(

+

x = {

+

// we need extreme values for fast oscillation

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+


+

// for t0, y0 default values are taken

+

sig = Fb1_ODE.ar(\MSD, 

+

[f, mass, spring, dampen],

+

leakDC: false

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+


+

// for audible sound production take a time multiplier and a scaling factor

+

// and get a decaying sine, leakDC now true by default

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_ODE.ar(\MSD, [f, mass, spring, dampen], tMul: 10);

+

Line.kr(dur: 10, doneAction: 2);

+

sig[0] * 20

+

}.play

+

)

+


+

x.release

+


+


+

// as MSD is predefined together with the wrapper class Fb1_MSD

+

// one can equivalently write

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_MSD.ar(f, mass, spring, dampen, tMul: 10);

+

Line.kr(dur: 10, doneAction: 2);

+

sig[0] * 20

+

}.play

+

)

+


+

x.release

+


+


+

Ex.2) Numeric integration type

+

+

// For most cases the symmetric symplectic procedures with prefix 'sym' should be used (default 'sym2').

+

// They deliver best results with regard to long-term stability, see links at top.

+

// In case you suspect instability coming from numerics 

+

// you can take symplectic variants of higher order: 

+

// \sym2, \sym4, \sym6, \sym8, \sym12, \sym16, \sym32, \sym64.

+


+

// Note that already a simple harmonic oscillator can fail with a standard procedure

+


+

// This is decaying after a few seconds with classical Runge-Kutta 3rd order !

+

// ATTENTION: with other non-symplectic procedures this can lead to immediate blowups !

+

// Euler variants are especially bad.

+


+

(

+

Fb1_ODEdef(\harmonic, { |t, y|

+

[y[1], y[0].neg]

+

}, 0, [0, 1], 1, 1); 

+

)

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\harmonic,

+

tMul: 1000 * 2pi,

+

intType: \rk3

+

);

+

Limiter.ar(sig) * 0.1 * EnvGen.ar(Env.asr(0.1, curve: 3))

+

}.play

+

)

+


+

x.release

+


+


+
Examples 3) Modulations

+


+

// All optional arguments of the Fb1_ODE can take UGens at audio or control rate,

+

// tMul can be modulated at both rates as well.

+


+


+

Ex.3a) Argument modulation

+

+

// additional oscillation of mass, this is already a quite extreme blurring

+

// operations of such kind can easily result in derailing the oscillaton

+


+

// here it's interesting to hear quite a difference between ar and kr variants

+


+

// ar modulation

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_ODE.ar(\MSD, 

+

[f, mass * LFTri.ar(200).range(0.1, 2), spring, dampen],

+

leakDC: false

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1)

+

}.play

+

)

+

+

x.release

+


+


+

// much less smooth with kr

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_ODE.ar(\MSD, 

+

[f, mass * LFTri.kr(200).range(0.1, 2), spring, dampen],

+

leakDC: false

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+


+

// due to Fb1's design, above kr modulator is not interpolated

+

// an interpolated kr variant though gives an even more blurred result 

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_ODE.ar(\MSD, 

+

[f, mass * K2A.ar(LFTri.kr(200).range(0.1, 2)), spring, dampen],

+

leakDC: false

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+


+

Ex.3b) Time modulation

+


+


+

// kr modulation of time

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_ODE.ar(\MSD, 

+

[f, mass, spring, dampen],

+

tMul: SinOsc.kr(0.6).range(0.5, 1.5),

+

leakDC: false

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+

// ar modulation of time

+

// including mainly negative multipliers

+

// questionable physical sense, but can be fun

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+

sig = Fb1_ODE.ar(\MSD, 

+

[f, mass, spring, dampen],

+

tMul: SinOsc.ar(5).range(-5, 1.5),

+

leakDC: false,

+

withTimeChannel: true // include time as third channel

+

);

+

sig[2].poll;

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1);

+

}.play

+

)

+


+

x.release

+


+


+

Ex.4) Initial values

+

+

// Initial values - system state y0 at time t0: y(t0) = y0 - are essential for an ODE solution.

+

// In this example with the MSD model (and constant f !) time isn't explicit,

+

// therefore it makes no difference if we start at t = 0 or t = 10, time is only shifted.

+


+

// However the position, described here by y, is time-dependent,

+

// so it makes a difference to start with different values

+


+

// y'(t) = w(t)

+

// w'(t) = (f(t) - (dampen * w(t)) - (spring * y(t))) / mass

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 50, dampen = 0.0005,

+


+

sig = Fb1_ODE.ar(\MSD,

+

[f, mass, spring, dampen],

+

t0: 10,  // this doesn't make a difference to default 0

+

y0: [0.2, 0],  // this does ! (compare with default [0, 0])

+

leakDC: false

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.005, [100, 101], 700), 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+


+

Examples 5) The 'compose' argument

+


+

// This allows to build an additional Function into the Fb1 feedback loop.

+

// It is applied to every array of samples that is result and 

+

// next input of the numeric integration procedure.

+

// Obviously then correct integration of the ODE cannot be performed anymore, 

+

// but the option has still its value. 

+


+


+

Ex.5a) Handling instable systems

+


+

// mass spring damper with extra term y[0] * y[1] -

+

// out of interest, no physical argument for that

+


+

(

+

Fb1_ODEdef(\MSD_2, { |t, y, f = 0, mass = 1, spring = 1, dampen = 0|

+

[

+

y[1], 

+

f - (dampen * y[1]) - (spring * y[0]) + (y[0] * y[1]) / mass

+

]

+

}, 0, [0, 0], 1, 1);

+

)

+


+


+

// System derails after some seconds and produces nans.

+


+

(

+

x = {

+

    var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

    var sig = Fb1_ODE.ar(\MSD_2, [f, mass, spring, dampen], leakDC: false).poll;

+

    LeakDC.ar(SinOsc.ar(sig[0].linlin(0, 0.006, [50, 50.1], 700), 0, 0.1))

+

}.play

+

)

+


+

x.release

+


+


+


+

// Keeping the system alive with clipping at LFO-controlled frequency.

+

// Note that the compose Function is passed an array as size of MSD_2 is 2,

+

// clip2 applied to an array again returns an array which is necessary,

+

// the Function must preserve the system size.

+


+

(

+

x = {

+

var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

var lfo = LFDNoise3.kr(2).exprange(0.2, 1500);

+

var sig = Fb1_ODE.ar(\MSD_2, 

+

[f, mass, spring, dampen], 

+

leakDC: false,

+

compose: { |y| y.clip2(lfo) }

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.006, [50, 50.1], 700).poll, 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+


+

// if an operator is passed via a Symbol, it applies to all channels

+


+

(

+

x = {

+

var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

var sig = Fb1_ODE.ar(\MSD_2, 

+

[f, mass, spring, dampen], 

+

leakDC: false,

+

compose: \softclip

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.006, [50, 50.1], 700).poll, 0, 0.1)

+

}.play

+

)

+


+

x.release

+


+


+

Ex.5b) Other options of the 'compose' argument

+


+

// You might want to pass ar signals to the composition Function.

+

// This has to be done via the composeArIn argument, 

+

// its UGens are then passed as second argument to the compose Function.

+


+

// This somewhat odd way of passing is necessary as feeding ar signals into Fb1 is not trivial

+

// and must also be done via an extra 'in' argument - which in turn is used by Fb1_ODE.

+


+

(

+

x = {

+

var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

var mod = SinOsc.ar(SinOsc.ar(LFDNoise3.ar(0.1).range(50, 1000)).range(10, 5000), 0, 0.1, 1);

+

var sig = Fb1_ODE.ar(\MSD,

+

[f, mass, spring, dampen],

+

leakDC: false,

+

compose: { |y, in| (y * in).tanh },

+

composeArIn: mod

+

);

+

SinOsc.ar(sig[0].linlin(0, 0.006, [50, 50.1], 700), 0, 0.07)

+

}.play

+

)

+


+

x.release

+


+


+

// note that above operation is totally different from applying the ring modulation + tanh

+

// after the integration, here the feedback process is much simpler:

+


+

(

+

x = {

+

var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

var mod = SinOsc.ar(SinOsc.ar(LFDNoise3.ar(0.1).range(50, 1000)).range(10, 5000), 0, 0.1, 1);

+

var sig = (Fb1_ODE.ar(\MSD,

+

[f, mass, spring, dampen],

+

leakDC: false

+

) * mod).tanh;

+

SinOsc.ar(sig[0].linlin(0, 0.006, [50, 50.1], 700), 0, 0.07)

+

}.play

+

)

+


+

x.release

+


+


+

// The compose arg can also take an array of Functions and/or operators,

+

// the composeArIn arg can take an array of UGens,

+

// the compose Function(s) can refer to the components of the passed arrays. 

+


+

(

+

x = {

+

var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

var mod = SinOsc.ar(SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(50, 100)).range(10, 5000), 0, 0.1, 1);

+

var sig = Fb1_ODE.ar(\MSD,

+

[f, mass, spring, dampen],

+

leakDC: false,

+

compose: [

+

{ |y, in| (y[0] * in[0]).softclip },

+

{ |y, in| ((y[0] + y[1]) * in[1]).softclip }

+

],

+

composeArIn: mod // mod is a stereo signal !

+

);

+

SinOsc.ar(sig[0..1].linlin(0, 0.006, 50, LFDNoise1.ar(0.1).range(700, 2000)), 0, 0.05)

+

}.play

+

)

+


+

x.release

+


+


+

// composeArIn's array can contain arrays also

+


+

(

+

x = {

+

var f = 0.5, mass = 0.001, spring = 150, dampen = 0.001;

+

var mod0 = Saw.ar(LFDNoise1.ar(1).exprange(3, 3000), 0.05);

+

var mod1 = SinOsc.ar(SinOsc.ar(LFDNoise3.ar(1 ! 2).range(1, 20)).range(1, 3000), 0, 0.1, 1);

+

var sig = Fb1_ODE.ar(\MSD,

+

[f, mass, spring, dampen],

+

leakDC: false,

+

compose: [

+

{ |y, in| (y[0] * in[1][0]).softclip },

+

{ |y, in| ((y[0] + y[1]) * in[1][1] + in[0]).softclip }

+

],

+

composeArIn: [mod0, mod1] // mod1 is itself a stereo signal !

+

);

+

SinOsc.ar(sig[0..1].linlin(0, 0.006, 50, LFDNoise1.ar(0.1).range(700, 1500)), 0, 0.05);

+

}.play

+

)

+


+

x.release

+


+


+


+

Examples 6) Channels with additional information

+


+

Ex.6a) The differential channels 

+

+

// The optional differential channel(s) contain the differential(s) at time t,

+

// in other terms: the value(s) F(t, Y) of the system

+

// Y'(t) = F(t, Y)

+


+

// For many numeric integration methods these values are buffered anyway,

+

// but not for the symplectic procedures.

+

// Therefore there exist variants with suffix '_d' which can be used in that case

+


+

// an oscillation produced by a Hopf ODE (see also Fb1_Hopf)

+

+

(

+

x = {

+

Fb1_ODE.ar(\Hopf,

+

[1, 2, 1],

+

1000,

+

intType: \sym2_d, // no difference to sym2 in the first two channels

+

) * 0.5

+

}.play

+

)

+


+

x.release

+

+

// The system has size two, so with differential we get 4 out channels,

+

// take the differential only, it gives a different sound colour (more partials).

+

+

(

+

x = {

+

Fb1_ODE.ar(\Hopf,

+

[1, 2, 1],

+

1000,

+

intType: \sym2_d,

+

withDiffChannels: true,

+

)[2..3] * 0.5

+

}.play

+

)

+


+

x.release

+

+

+

// The differential channels are basically buffering the slope of the 

+

// original (integration/solution) signal as a by-product, 

+

// slope could also be calculated with the Slope UGen.

+

// Note that we scaled time by a factor 1000, so the result of Slope

+

// has to be divided by the same factor.

+

+

(

+

x = {

+

Slope.ar(

+

Fb1_ODE.ar(\Hopf,

+

[1, 2, 1],

+

1000,

+

intType: \sym2_d,

+

withDiffChannels: true

+

)[0..1] * 0.5

+

) / 1000

+

}.play

+

)

+


+

x.release

+

+

+

Ex.6b) The time channel

+

+

// tMul also multiplies the integrated time, so here we proceed with 500 * 2pi per second ...

+


+

(

+

Fb1_ODEdef(\harmonic, { |t, y|

+

[y[1], y[0].neg]

+

}, 0, [0, 1], 1, 1); 

+

)

+

+

(

+

x = { 

+

var sig = Fb1_ODE.ar(\harmonic, 

+

tMul: 500 * 2pi,

+

withTimeChannel: true

+

);

+

sig[2].poll;

+

sig[0..1] * 0.1 // don't want to have time as audio output !

+

}.play

+

)

+

+

x.release

+

+

+

// ... whereas here time is scaled by the ODE

+

+

(

+

Fb1_ODEdef(\harmonic_2, { |t, y|

+

[y[1], y[0].neg] * 500 * 2pi

+

}, 0, [0, 1], 1, 1); 

+

)

+

+

(

+

x = { 

+

var sig = Fb1_ODE.ar(\harmonic_2, 

+

tMul: 1,

+

withTimeChannel: true

+

);

+

sig[2].poll;

+

sig[0..1] * 0.1 // don't want to have time as audio output !

+

}.play

+

)

+

+

x.release

+


+

+

// time integration might be of interest with modulations of tMul

+

+

(

+

x = {

+

var sig = Fb1_ODE.ar(\harmonic_2,

+

tMul: SinOsc.kr(0.2).exprange(0.2, 2),

+

withTimeChannel: true

+

);

+

sig[2].poll;

+

sig[0..1] * 0.07 // don't want to have time as audio output !

+

}.play

+

)

+


+

x.release

+


+


+

Ex.7) The 'withOutScale' argument

+


+


+

// It determines if default scaling parameters for the ODE integration signal and differential(s) should be applied

+

// In many cases this doesn't make a difference when the default scaling values equal 1.

+


+

// Certain ODEs though produce a very high amplitude level with usual standard params, like Lorenz.

+

// So it makes sense to scale the output down by default.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\Lorenz, { |t, y, s = 10, r = 30, b = 2|

+

[

+

{ (y[1] - y[0]) * s },

+

{ (r - y[2]) * y[0] - y[1] },

+

{ (y[0] * y[1]) - (b * y[2]) }

+

]

+

}, 0, [1, 1, 1], 0.01, 0.01); // scaling parameters 0.01

+


+


+

// So there's no problem to use Lorenz with standard params as

+

// 'withOutScale' defaults to true

+


+

(

+

x = {

+

var s = 10, r = 30, b = 3, tMul = MouseX.kr(50, 150, 1).poll,

+

sig;

+

sig = Fb1_ODE.ar(\Lorenz, [s, r, b], tMul);

+

sig[0..1]

+

}.play;

+

)

+


+

x.release

+


+


+

// WARNING: it's not recommended to set 'withOutScale' to false

+

// as in cases like this you get very high levels !

+

// So here we have to reduce the level outside the Fb1_ODE

+


+

(

+

x = {

+

var s = 10, r = 30, b = 3, tMul = MouseX.kr(50, 150, 1).poll,

+

sig;

+

sig = Fb1_ODE.ar(\Lorenz, [s, r, b], tMul, withOutScale: false);

+

sig[0..1] / 100

+

}.play;

+

)

+


+

x.release

+


+


+

// WARNING: 'withOutScale' does not implement a general safety net functionality, 

+

// withOutScale's default value true does by no means say that output is limited. 

+

// The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

// under different circumstances, always lead to high out levels. 

+


+


+

+

Examples 8) ODEs from mechanics

+


+

Ex.8a) The driven pendulum

+


+

// The driven pendulum is interesting as it's a quite simple model

+

// that includes parameter zones of chaotic behaviour:

+

// http://lampx.tugraz.at/~hadley/physikm/apps/numerical_integration/pendulum.en.php

+


+

// y here denotes the angle

+


+

// y''(t) + (y'(t) / q) + sin(y(t)) = a * cos(omega * t)

+


+

// which translates to

+


+

// y'(t) = w(t)

+

// w'(t) = (-w(t) / q) - sin(y(t)) + (a * cos(omega * t))

+


+


+

(

+

Fb1_ODEdef(\DrivenPendulum, { |t, y, q = 1, omega = 0, a = 1|

+

[

+

{ y[1] },

+

{ y[1] / q.neg - sin(y[0]) + (a * cos(omega * t)) }

+

]

+

}, 0, [0, 0], 1, 1);

+

)

+


+


+

// move the mouse through a zone of chaotic behaviour between 0.65 and 0.68

+


+

(

+

x = { 

+

var sig = Fb1_ODE.ar(\DrivenPendulum, [2.3, MouseX.kr(0.65, 0.68).lag(2).poll, 1.6],

+

2000,

+

0, [0, 1],

+

);

+

sig.poll;

+

sig[1] ! 2 * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

Ex.8b) The reduced two body problem

+


+

// Two planets are moving around the common barycenter, thus the system can be simplified

+

// to an ODE which describes the changes of the the relative vector between the masses.

+


+

// E.g. see https://evgenii.com/blog/two-body-problem-simulator

+


+


+

(

+

Fb1_ODEdef(\TwoBodyReduced, { |t, y, m1, m2|

+

var v = -1 - (m1 / m2);

+

var r = y[0..1].squared.sum.sqrt;

+

[

+

{ y[2] },

+

{ y[3] },

+

{ v * y[0] / r.cubed },

+

{ v * y[1] / r.cubed }

+

]

+

}, 0, [0, 0, 0, 0], 1, 1);

+

)

+


+

// It turns out that this system is numerically very sensitive.

+

// Standard procedures are failing soon: here classical Runge-Kutta 4rth order

+

// leads to a glissando before it collapses.

+

// Even 2nd order symplectic shows movement of wave forms, 

+

// though it keeps frequency and preserves volume 

+


+

// here we take only the first two components which represent the plane coordinates

+

// of the difference vector

+


+

// sym8 still shows a slow morphing of wave forms

+

// you can try with \sym64, very inefficient, but even more steady

+


+

(

+

x = {

+

var m = [1, 1.5];

+

Fb1_ODE.ar(\TwoBodyReduced, m,

+

100, 0, [0, 0.2, 2, 1],

+

intType: \sym8

+

)[0..1]

+

}.play

+

)

+


+

s.scope

+


+

x.release

+


+


+

Examples 9) ODEs from population dynamics

+


+

Ex.9a) The Lotka-Volterra equations

+


+

// They describe populations of predators and prey, e.g. foxes and rabbits.

+

// https://en.wikipedia.org/wiki/Lotka%E2%80%93Volterra_equations

+


+


+

// v'(t) = (alpha * v(t)) - (beta * v(t) * w(t))

+

// w'(t) = (delta * v(t) * w(t)) - (gamma * w(t))

+


+


+

(

+

Fb1_ODEdef(\LotkaVolterra, { |t, y, alpha = 0.1, beta = 0.1,

+

gamma = 0.1, delta = 0.1|

+

[

+

{ y[0] * (beta.neg * y[1] + alpha) },

+

{ y[1].neg * (delta.neg * y[0] + gamma) }

+

]

+

}, 0, [1, 1], 1, 1);

+

)

+


+

// with standard parameter usage the audio results are brass-like and not spectacular

+


+

(

+

x = {

+

Fb1_ODE.ar(\LotkaVolterra,

+

[0.2, MouseX.kr(0.1, 0.9), MouseY.kr(0.1, 0.9), 0.8],

+

tMul: 3000

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

Ex.9b) The Hastings-Powell equations

+


+

// This is an extension of the Lotka-Volterra model and

+

// considers the fact that rabbits must eat too.

+

// It is described in the article

+


+

// Alan Hastings and Thomas Powell (1991). 

+

// "Chaos in a Three-Species Food Chain" Ecology 72(3): 896-903

+


+

// and on page 165 of the book "Exploring ODEs"

+


+

// Trefethen, Lloyd N.; Birkisson, Ásgeir; Driscoll, Tobin A. (2017):

+

// Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics

+

// Free download from:

+

// http://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+


+

// We take over initial values and parameters from the example given there:

+


+

(

+

Fb1_ODEdef(\CarrotsRabbitsFoxes, { |t, y, a1 = 5, a2 = 0.1,

+

b1 = 0.1, b2 = 2, d1 = 0.4, d2 = 0.01|

+

var p = a1 * y[0] / (1 + (b1 * y[0])) * y[1];

+

var q = a2 * y[1] / (1 + (b2 * y[1])) * y[2];

+

[

+

{ y[0] * (1 - y[0]) - p }, // carrots

+

{ p - q - (d1 * y[1])  }, // rabbits

+

{ q - (d2 * y[2])  } // foxes

+

]

+

}, 0, [0.4, 1, 9], 1, 1);

+

)

+


+


+

// In stereo we hear population oscillations of carrots and rabbits,

+

// it takes some fractions of a second at begin after a state is reached.

+

// Check with mouse and see post window:

+

// b1 goes through a zone of chaotic behaviour between 2.5 and 3.5

+


+

(

+

x = {

+

var a1 = 5, a2 = 0.1, b1 = MouseX.kr(2.5, 3.5).poll, b2 = 2,

+

d1 = 0.4, d2 = 0.01, tMul = 5000, amp = 0.2;

+

Fb1_ODE.ar(\CarrotsRabbitsFoxes,

+

[a1, a2, b1, b2, d1, d2],

+

tMul, 0, [0.4, 1, 9]

+

)[0..1] * amp

+

}.play

+

)

+


+

x.release

+


+


+


+


+ + diff --git a/Help/Fb1_ODEdef.html b/Help/Fb1_ODEdef.html new file mode 100755 index 0000000..22116b9 --- /dev/null +++ b/Help/Fb1_ODEdef.html @@ -0,0 +1,441 @@ + + + + + + + + + + + +

Fb1_ODEdef container for ordinary differential equation definitions

+


+

Part of: miSCellaneous

+


+

To be used to define ODE systems that can then be audified with Fb1_ODE. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [2], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [3]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE help Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: Fb1_ODE in its plain form (without tMul modulation, use of compose etc.) produces audio data as a numerical integration of an ODE initial value problem, defined by Fb1_ODEdef and a numerical procedure, defined by Fb1_ODEintdef. This of course supposes well-defined ODE systems and it should be kept in mind that the Fb1_ODE framework doesn't perform any mathematical checks regarding the principal existence and uniqueness of a solution of a given Fb1_ODEdef. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (name, function, t0, y0, outScale = 1, diffOutScale = 1)

+

+

Creates a new Fb1_ODEdef object and stores it in a Dictionary for further usage with Fb1_ODE.

+

+

name - The name of the ODE, expects a Symbol.

+

Default Fb1_ODEdefs cannot be overwritten.

+

function - The implementation of the function F which describes the ODE given as 

+

Y'(t) = F(t, Y(t)) where Y, F can be a single-valued or vector-valued.

+

It must take time as first and a system state (possibly an array) as second parameter 

+

and optional further args that can also be arrays.

+

The system state is expected to have the size of the system (given by y0's size), 

+

the function's return value must also equal this size.

+

If the system size is greater than 1 the components of the output array

+

should be rather written as Functions, as this optimizes the compile process

+

with symplectic integration procedures, it isn't compulsory though.

+

See examples below and in the source file Fb1_ODEdef.sc.  

+

t0 - Number. Default initial time value. 

+

y0 - Default initial value of the ODE. 

+

Expects number or array and determines the size of the system, function's second arg

+

and return value must be of same size.

+

outScale - Number that determines the default multiplier for the integration signal 

+

produced by Fb1_ODE when the latter's withOutScale flag is set to true (default).

+

Defaults to 1. Especially thought for systems like Lorenz which produce high levels

+

with standard parameters, then it makes sense to set outScale to a value smaller than 1.

+

WARNING: outScale / diffOutScale / withOutScale do not implement a 

+

general safety net functionality, withOutScale's default value true does by no means say 

+

that output is limited. Scaling values of Fb1_ODEdefs can only be average assumptions and can, 

+

under different circumstances, always lead to high out levels.

+

diffOutScale - Number that determines the default multiplier for the differential signal 

+

produced by Fb1_ODE when the latter's withOutScale flag is set to true (default).

+

Defaults to 1. Especially thought for systems like Lorenz which produce high levels

+

with standard parameters, then it makes sense to set diffOutScale to a value smaller than 1.

+

WARNING: outScale / diffOutScale / withOutScale do not implement a 

+

general safety net functionality, withOutScale's default value true does by no means say 

+

that output is limited. Scaling values of Fb1_ODEdefs can only be average assumptions and can, 

+

under different circumstances, always lead to high out levels.

+


+


+

*at (key)

+

+

Returns the Fb1_ODEdef instance of the Symbol key if it exists.

+


+

*keys

+

+

Returns an array of all keys of currently stored Fb1_ODEdefs.

+

+

*postAll

+

+

Posts all keys of currently stored Fb1_ODEdefs.

+


+

*remove (key)

+

+

Removes the Fb1_ODEdef of the Symbol key from the Dictionary.

+

+

*reset

+

+

Removes all Fb1_ODEdefs other than the predefined ones from the Dictionary.

+

+


+

+

Instance Methods

+


+

next (intType, t, y, dt, args)

+

+

Method for language-side integration, gives next value based on previous data.

+

+

intType - Integration type.

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym', like 'sym2') is highly recommended.

+

For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Multi-step procedures are not implemented, remaining:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

t - Previous time, expects Number.

+

y - Previous state, expects Number or Array of system size.

+

dt - Number. Time delta. 

+

args - List of additional args to be passed to Fb1_ODEdef's function.

+


+


+

nextN (n, intType, t, y, dt, args, withTime = false, includeStart = true)

+

+

Method for language-side integration, gives an array of next n values (arrays) based on previous data.

+

Last values (arrays) are stored at last position. For intTypes with sizeFactor 2 the differential is included.

+

See Examples.

+

+

n - Integer. Number of next values (resp. value arrays) to be calculated.

+

intType - Integration type.

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym', like 'sym2') is highly recommended.

+

For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Multi-step procedures are not implemented, remaining:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

t - Previous time, expects Number.

+

y - Previous state, expects Number or Array of system size.

+

dt - Number. Time delta. 

+

args - List of additional args to be passed to Fb1_ODEdef's function.

+

withTime - Boolean. Determines if integrated time should be included. 

+

Defaults to false.

+

includeStart - Boolean. Determines if start value(s) should be included.

+

Defaults to true.

+


+


+

name 

+

+

Getter for the Fb1_ODEdef's name.

+


+

function 

+

+

Getter for the Fb1_ODEdef's function.

+


+

t0 

+

+

Getter for the Fb1_ODEdef's t0.

+


+

y0 

+

+

Getter for the Fb1_ODEdef's y0.

+


+

outScale 

+

+

Getter for the Fb1_ODEdef's outScale.

+


+

diffOutScale 

+

+

Getter for the Fb1_ODEdef's diffOutScale.

+


+

size 

+

+

Getter for the Fb1_ODEdef's system size.

+


+

+


+

Examples 1) Defining new ODEs

+


+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+


+

Ex.1a) Extending the harmonic oscillator

+


+

// This seems to be an interesting strategy.

+

// We can e.g. try to multiply one of its equations with a term near 1,

+

// so start with rather small k and investigate

+


+

// y'(t) = w(t)

+

// w'(t) = -y(t) * (1 + (k * w(t))

+


+

 

+

(

+

Fb1_ODEdef(\harmonic_ext_1, { |t, y, k|

+

[

+

y[1], 

+

y[0].neg * (1 + (k * y[1]))

+

]

+

}, 0, [0, 1], 1, 1); 

+

)

+


+


+

// brassy sound

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\harmonic_ext_1,

+

[1], 1500, 0, [0, 1],

+

) * 0.1;

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

// with oscillating k the system tends to become unstable

+

// but with softclip per sample it can be kept 

+

// (see chapter 'compose' option in Fb1_ODE help)

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\harmonic_ext_1,

+

// k oscillates between 1 and 3

+

[SinOsc.ar(50).lincurve(-1, 1, 1, 3, 2)],

+

1500, 0, [0, 1],

+

compose: \softclip

+

) * 0.1;

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

// an oscillation between 1 and higher values totally changes the spectrum

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\harmonic_ext_1,

+

// k oscillates between 1 and 10

+

[SinOsc.ar(50).lincurve(-1, 1, 1, 10, 2)],

+

1500, 0, [0, 1],

+

compose: \softclip

+

) * 0.1;

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

// play with the two states

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\harmonic_ext_1,

+

// upper oscillation bound for k oscillates itself between 2 and 15

+

[SinOsc.ar(50).lincurve(-1, 1, 1, SinOsc.ar(SinOsc.ar(0.2).exprange(0.2, 15)).range(2, 15), 2)],

+

1500, 0, [0, 1],

+

compose: \softclip

+

) * 0.1;

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

Ex.1b) Extending exponential decay

+


+

// exponential decay is described by the equation

+

// y'(t) = -y(t)

+


+

// an oscillating decay can e.g. be got by

+

// y'(t) = -y(t) * sin(t)

+

// the analytic solution includes a log of the sine,

+

// so we get more partials

+


+


+

(

+

Fb1_ODEdef(\exp_decay_raw, { |t, y|

+

y.neg * sin(t)

+

}, 0, 1, 1, 1);

+

)

+


+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\exp_decay_raw,

+

tMul: 100 * 2pi,

+

compose: \softclip

+

) ! 2;

+

Line.kr(dur: 10, doneAction: 2);

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

// multiplication with a second sine with multiplied time leads to strange and interesting results

+


+

(

+

Fb1_ODEdef(\exp_decay_extended, { |t, y, k|

+

y.neg * (sin(t) * sin(k * t))

+

}, 0, 1, 1, 1);

+

)

+


+


+


+

// ATTENTION: danger of blowup, can be reduced with softclip composition per sample

+

// constant values lead to ring modulation-like effects ...

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\exp_decay_extended,

+

[2.7], 100 * 2pi, 0, 1,

+

compose: \softclip

+

);

+

Line.kr(dur: 10, doneAction: 2);

+

sig ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// ... whereas modulations produce more complex changing spectra

+

(

+

x = {

+

var sig = Fb1_ODE.ar(\exp_decay_extended,

+

[SinOsc.ar(120).range(3, 3.01)], 100 * 2pi, 0, 1,

+

compose: \softclip

+

);

+

Line.kr(dur: 10, doneAction: 2);

+

sig ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// for decorrelated stereo we can expand to two independent equations

+

// k should be of size 2

+


+

(

+

Fb1_ODEdef(\exp_decay_extended_2, { |t, y, k|

+

[

+

y[0].neg * (sin(t) * sin(k[0] * t)),

+

y[1].neg * (sin(t) * sin(k[1] * t))

+

]

+

}, 0, [1, 1], 1, 1);

+

)

+


+

(

+

x = {

+

var sig = Fb1_ODE.ar(\exp_decay_extended_2,

+

[SinOsc.ar(120).range([3, 3.01], [3.01, 3.02])], 100 * 2pi, 0, [1, 1],

+

compose: \softclip

+

);

+

Line.kr(dur: 10, doneAction: 2);

+

sig

+

}.play

+

)

+


+

x.release

+


+


+

Ex.2) Language-side integration

+


+

// Possible though not optimized.

+

// For longer sections it's probably better to employ Fb1 ODE solvers, 

+

// store audio in a buffer and load it into a float array,

+

// for quick tests it might be useful though. 

+


+

// integrate begin of a Lorenz system, last array is last state, so flop for plot

+


+

(

+

a = Fb1_ODEdef.at(\Lorenz).nextN(

+

n: 1000,

+

intType: \sym2,

+

t: 0, 

+

y: [1, 1, 1],

+

dt: 1/100,

+

args: [30, 12, 2]

+

);

+


+

a.flop.plot

+

)

+


+


+


+


+ + diff --git a/Help/Fb1_ODEintdef.html b/Help/Fb1_ODEintdef.html new file mode 100755 index 0000000..d2923ca --- /dev/null +++ b/Help/Fb1_ODEintdef.html @@ -0,0 +1,180 @@ + + + + + + + + + + + +

Fb1_ODEintdef container for ordinary differential equation numeric integrators

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

For the optional definition of ODE integration procedures that can then be used with Fb1_ODE. This is an advanced feature, the built-in symplectic procedures should suffice for most use cases. See the source code in Fb1_ODEintdef.sc for the way integrators are defined and Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [2], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [3]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE help Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: Fb1_ODE in its plain form (without tMul modulation, use of compose etc.) produces audio data as a numerical integration of an ODE initial value problem, defined by Fb1_ODEdef and a numerical procedure, defined by Fb1_ODEintdef. This of course supposes well-defined ODE systems and it should be kept in mind that the Fb1_ODE framework doesn't perform any mathematical checks regarding the principal existence and uniqueness of a solution of a given Fb1_ODEdef. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (name, function, stepDepth = 1, sizeFactor = 1)

+

+

Creates a new Fb1_ODEintdef object and stores it in a Dictionary for further usage with Fb1_ODE.

+

+

name - The name of the integration procedure, expects a Symbol.

+

Default Fb1_ODEintdefs cannot be overwritten.

+

function - The implementation of the Function ("stepper") which describes the numeric procedure. 

+

It must take the arguments odeDef, t, y, dt and ... args for further ODE args and

+

must return the new integration value(s). For evaluating the ODE function 

+

the method Fb1_ODEdef::value is used which performs the evaluation depending on its first argument.

+

stepDepth - Integer. Values greater than one are for multi-step procedures. 

+

Defaults to 1. 

+

sizeFactor - Integer. 1 means that the procedure buffers only integration values,

+

2 means that the differential is buffered too. 

+

Defaults to 1. 

+


+


+

*at (key)

+

+

Returns the Fb1_ODEintdef instance of the Symbol key if it exists.

+


+

*keys

+

+

Returns an array of all keys of currently stored Fb1_ODEintdefs.

+

+

*postAll

+

+

Posts all keys of currently stored Fb1_ODEintdefs.

+


+

*remove (key)

+

+

Removes the Fb1_ODEintdef of the Symbol key from the Dictionary.

+

+

*reset

+

+

Removes all Fb1_ODEintdefs other than the predefined ones from the Dictionary.

+

+


+

+

Instance Methods

+


+

name 

+

+

Getter for the Fb1_ODEintdef's name.

+


+

function 

+

+

Getter for the Fb1_ODEintdef's function.

+


+

stepDepth

+

+

Getter for the Fb1_ODEintdef's stepDepth.

+


+

sizeFactor 

+

+

Getter for the Fb1_ODEintdef's sizeFactor.

+


+

+


+

Examples

+


+

// This shows how the classical 4-step Runge-Kutta is implemented,

+

// quite straight it follows its mathematical definition.

+


+

// t: the old time

+

// y: the old state (array)

+

// dt: the integration step

+

// size: the size of the ODE (not used here, but needs to be there)

+

// ... args is for further args of the ODE

+


+

// The odeDef argument expects the Fb1_ODEdef object.

+

// The evaluation of the ODE function is implemented by odeDef::value.

+

// This method takes a first argument i which determines the kind of evaluation:

+

// For i == nil it returns the evaluation value(s) as Array,

+

// for a number it only returns the ith component.

+

// The distinction is necessary as the symplectic procedures refer to

+

// the single components of the ODE system.

+


+

// There exist also symplectic Runge-Kutta procedures which I didn't test so far.

+

// they would probably also need that option.

+


+

Fb1_ODEintdef(\rk4,

+

{ |odeDef, t, y, dt, size ... args|

+

var k1 = odeDef.(nil, t, y, *args);

+

var k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + y, *args);

+

var k3 = odeDef.(nil, dt * 0.5 + t, k2 * dt * 0.5 + y, *args);

+

var k4 = odeDef.(nil, dt + t, k3 * dt + y, *args);

+

((k2 + k3) * 2 + k1 + k4) * dt / 6 + y

+

}, 1, 1);

+


+


+

// The same procedure as '_d' variant which stores the differential

+

// The argument y is now passed an array of doubled size with the

+

// last differential values in the second half of it.

+

// Finally the new differential value is calculated and appended to the integration.

+


+

Fb1_ODEintdef(\rk4_d,

+

{ |odeDef, t, y, dt, size ... args|

+

var k1, k2, k3, k4, yy, ff, yNew, fNew;

+

yy = y[0..size-1];

+

ff = y[size..2*size-1];

+

k1 = ff;

+

k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + yy, *args);

+

k3 = odeDef.(nil, dt * 0.5 + t, k2 * dt * 0.5 + yy, *args);

+

k4 = odeDef.(nil, dt + t, k3 * dt + yy, *args);

+

yNew = ((k2 + k3) * 2 + k1 + k4) * dt / 6 + yy;

+

fNew = odeDef.(nil, t + dt, yNew, *args);

+

yNew ++ fNew

+

}, 1, 2);

+


+ + diff --git a/Help/Fb1_SD.html b/Help/Fb1_SD.html new file mode 100755 index 0000000..a4a9f7b --- /dev/null +++ b/Help/Fb1_SD.html @@ -0,0 +1,325 @@ + + + + + + + + + + + +

Fb1_SD spring damper model pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Fb1_ODE wrapper for the spring damper equation of motion with unit mass:

+


+

y''(t) = f(t) - (dampen * y'(t)) - (spring * y(t)) 

+


+

It returns a 2-channel signal with position and velocity. Fb1_SD is slightly more efficient than Fb1_MSD and you can always rewrite. See Fb1_ODE help for general information about Fb1 ODE integrator UGens and further MSD examples.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [2], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [3]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. 

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_VanDerPol, Fb1_Duffing

+


+

References:

+


+

[1] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[2] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[3] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (f = 0, spring = 1, dampen = 0, tMul = 1, t0 = 0, y0 = #[0, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_SD ar object.

+

+

f - External force. Defaults to 0.

+

spring - Spring stiffness. Defaults to 1.

+

dampen - Dampening factor. Defaults to 0.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[0, 0].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, spring = 1, dampen = 0, tMul = 1, t0 = 0, y0 = #[0, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, spring = 1, dampen = 0, tMul = 1, t0 = 0, y0 = #[0, 0],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_SD kr object.

+

+

f - External force. Defaults to 0.

+

spring - Spring stiffness. Defaults to 1.

+

dampen - Dampening factor. Defaults to 0.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[0, 0].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\SD, { |t, y, f = 0, spring = 1, dampen = 0|

+

[

+

{ y[1] },

+

{ f - (dampen * y[1]) - (spring * y[0]) }

+

]

+

}, 0, [0, 0], 1, 1);

+


+


+


+

// 2nd channel (velocity) generates decaying sine wave

+

// (position does also, but is softer)

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 1500, dampen = 0.003,

+

sig = Fb1_SD.ar(f/mass, spring/mass, dampen/mass);

+

sig[1] ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// oscillation as external force

+

// stays while spring oscillation decays

+


+

(

+

x = {

+

var f = SinOsc.ar(500, 0, 0.3), mass = 0.001, spring = 1500, dampen = 0.003,

+

sig = Fb1_SD.ar(f/mass, spring/mass, dampen/mass);

+

sig[1] ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// SD as modulator, kr saves ugens

+

// usable if, as here, it produces rather low frequencies

+


+

(

+

x = {

+

var f = 0.2, mass = 0.001, spring = 200, dampen = 0.003,

+

sig = Fb1_SD.kr(f/mass, spring/mass, dampen/mass);

+

SinOsc.ar(sig[1].linlin(-1, 1, [100, 90], 700), 0, 0.2)

+

}.play

+

)

+


+

x.release

+


+


+


+ + diff --git a/Help/Fb1_VanDerPol.html b/Help/Fb1_VanDerPol.html new file mode 100755 index 0000000..1e3bf69 --- /dev/null +++ b/Help/Fb1_VanDerPol.html @@ -0,0 +1,348 @@ + + + + + + + + + + + +

Fb1_VanDerPol Van der Pol pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

Fb1_ODE wrapper for the Van der Pol ODE system with external f:

+


+

y'(t) = w(t)

+

w'(t) = f(t) + (mu * (1 - y(t)^2) * w(t)) - (theta^2 * y(t)) 

+


+

coming from the 2nd order equation

+


+

y''(t) = f(t) + (mu * (1 - y(t)^2) * y'(t)) - (theta^2 * y(t)) 

+


+

It returns a 2-channel signal. The parameter naming follows the convention of [2]. As described in [1] and [2] adaptive variants can be made in the same way as for Hopf and other oscillators. See Fb1_ODE help for general information about Fb1 ODE integrator UGens.

+


+

HISTORY AND CREDITS: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation [4], pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri [5]. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse.  

+


+

WARNING: The usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See Fb1_ODE Ex.5) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. 

+


+

NOTE: The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved.  

+


+

See also: Fb1_ODE, Fb1_ODEdef, Fb1_ODEintdef, Fb1, Fb1_MSD, Fb1_SD, Fb1_Lorenz, Fb1_Hopf, Fb1_HopfA, Fb1_HopfAFDC, Fb1_Duffing

+


+

References:

+


+

[1] Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): 

+

"Adaptive Frequency Oscillators and Applications". 

+

The Open Cybernetics and Systemics Journal, 3, 64-69.

+

https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access

+

Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html/

+

[2] Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): 

+

"Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". 

+

Frontiers in Neurorobotics. Published online 2017 Mar 21

+

https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full

+

[3] Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): 

+

Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics.

+

Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf

+

[4] Pirrò, David (2017). Composing Interactions. Dissertation. 

+

Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz.

+

Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf

+

[5] https://git.iem.at/davidpirro/henri

+


+


+

Creation / Class Methods

+


+

*new (f = 0, mu = 1, theta = 1, tMul = 1, t0 = 0, y0 = #[1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_VanDerPol ar object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

theta - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / sample duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr / ar UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym2. For more accurate integration you can try symplectic procedures of

+

higher order like \sym4, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-sample base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

A Function can optionally take a second argument which is for ar UGens passed via composeArIn.

+

composeArIn - ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both.

+

This is the way to use ar UGens within a Function passed to compose.

+

UGens are passed to the Function's second argument.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be derived from the default server's properties

+

(sample duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

blockSize - Integer, this should be the server blockSize. 

+

If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). 

+

So explicitely passing a blockSize should only be necessary in special cases,

+

e.g. when compiling before booting.

+

However for a pleasant workflow for ar usage it's recommended to use 

+

a reduced server blockSize in order to reduce SynthDef compile time.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+

 

+


+

*ar (f = 0, mu = 1, theta = 1, tMul = 1, t0 = 0, y0 = #[1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Equivalent to *new.

+

+

*kr (f = 0, mu = 1, theta = 1, tMul = 1, t0 = 0, y0 = #[1, 1],

+

intType = \sym2, compose, composeArIn, dt0, argList0, init_intType = \sym8,

+

withOutScale = true, withDiffChannels = false, withTimeChannel = false, blockSize,

+

graphOrderType = 1, leakDC = true, leakCoef = 0.995)

+

+

Creates a new Fb1_VanDerPol kr object.

+

+

f - Defaults to 0.

+

mu - Defaults to 1.

+

theta - Defaults to 1.

+


+

tMul - Time multiplier, which determines velocity of proceeding in the dynamic system.

+

The default value 1 means that the step delta of time equals 1 / control duration.

+

For getting audible oscillations you might, depending on the ODE definition, have to pass

+

much higher values. Can also be a kr UGen and might also be negative.

+

t0 - Initial time. Expects Number. 

+

Defaults to 0.

+

y0 - Initial value of the ODE. 

+

Expects array of size 2.

+

Defaults to #[1, 1].

+

intType - Integration type. 

+

Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef.

+

The use of symplectic procedures (with prefix 'sym') is highly recommended.

+

Defaults to \sym4. For more accurate integration you can try symplectic procedures of

+

higher order like \sym6, \sym8 etc. Families of integration procedures:

+

Symplectic: 

+

\sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, 

+

\sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d

+

Euler: 

+

\eu, \eu_d, \eum, \eum_d, \eui, \eui_d

+

Prediction-Evaluation-Correction: 

+

\pec, \pece, \pecec, \pecece

+

Runge-Kutta: 

+

\rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d

+

Adams-Bashforth: 

+

\ab2, \ab3, \ab4, \ab5, \ab6

+

Adams-Bashforth-Moulton: 

+

\abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66

+

compose - Operator(s) / Function(s) to be applied to the system value on a per-control-block base.

+

This of course blurs the numeric procedure but can be used for containing or in a creative way.

+

Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof.

+

The Functions are in any case expected to take an array (the system state) as first argument.

+

If only one Function is given it must output an array of same (system) size.

+

Within a SequenceableCollection a Function must output a value of size 0.

+

Within a SequenceableCollection an operator Symbol is applied only to the corresponding component.

+

dt0 - First time delta in seconds to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

In case of a multi-step procedure a dt0 value will be assumed from the default server's properties

+

(control duration * tMul).

+

argList0 - Initial argList value(s) to be used for the language-side calculation of 

+

first values of a multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

If no UGens are passed to argList, values will be assumed from passed argList Numbers.

+

init_intType - Integration type for language-side calculation of first values of a 

+

multi-step intType procedure.

+

This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred.

+

Defaults to \sym8.

+

withOutScale - Boolean. Determines if the Fb1_ODEdef's default scaling values for

+

integration and differential signals should be applied to the output.

+

Defaults to true.

+

WARNING: withOutScale does not implement a general safety net functionality, 

+

withOutScale's default value true does by no means say that output is limited. 

+

The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, 

+

under different circumstances, always lead to high out levels. 

+

withDiffChannels - Boolean. Determines if channel(s) with differential value(s) should be returned.

+

This is only applicable with integration types with a sizeFactor == 2, which means that for every sample

+

the values of the differential are buffered. As by default this is not the case for all predefined 

+

numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d.

+

Defaults to false.

+

withTimeChannel - Boolean. Determines if accumulated time is output in an additional channel. 

+

WARNING: with constant tMul it produces an ascending DC which is not affected by leakDC 

+

if this is set to true. Might especially be of interest if time is modulated.

+

Defaults to false.

+

graphOrderType - 0, 1 or 2. 

+

Determines if topological order of generated BufRd and BufWr instances

+

in the SynthDef graph is forced by additional UGens. 

+

Type 0: forced graph order is turned off.

+

Type 1 (default): graph order is forced by summation and <!.

+

Type 2: graph order is forced by <! operators only.

+

Default 1 is recommended, but with CPU-intense SynthDefs it might be worth trying it with the value 0. 

+

This saves a lot of UGens though there might be exceptional cases with different results.

+

Type 2 can shorten the SynthDef compilation time for certain graphs with a large number of UGens,

+

which can be lengthy with type 1.

+

However, CPU usage doesn't directly correspond to the number of UGens.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output (except time channel).

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+


+


+

Examples

+


+

// reboot with reduced blockSize

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.options.blockSize = 8;

+

s.reboot;

+

)

+


+

// In the source code of Fb1_ODEdef.sc the corresponding Fb1_ODEdef looks like this:

+

// the Function brackets within the array are not absolutely necessary, 

+

// but compile process is faster.

+


+

// don't evaluate, already stored

+


+

Fb1_ODEdef(\VanDerPol, { |t, y, f = 0, mu = 1, theta = 1|

+

var y0s;

+

y0s = y[0] * y[0];

+

[

+

{ y[1] },

+

{ mu * (1 - y0s) * y[1] + f - (theta * theta * y[0]) }

+

]

+

}, 0, [1, 1], 0.05, 0.05);  // scaling as standard params lead to high level output

+


+


+


+

// without external force

+

// control param mu (for high values of mu the oscillator crashes)

+

// mu == 0: harmonic oscillator

+


+

x = { Fb1_VanDerPol.ar(0, MouseX.kr(0, 3).poll, 1, 500) }.play

+


+

x.release

+


+


+


+

// sine source example with GUI

+


+

(

+

SynthDef(\VanDerPol, { |out, srcFreq = 1, srcAmp = 1, mu = 1, theta = 1, tMul = 1, amp = 1|

+

var sig;

+

sig = Fb1_VanDerPol.ar(

+

SinOsc.ar(srcFreq) * srcAmp,

+

mu, theta, tMul,

+

) * EnvGen.ar(Env.asr);

+

Out.ar(out, sig[0] ! 2 * amp)

+

}, metadata: (

+

specs: (

+

srcFreq: [30, 100, \lin, 1, 50],

+

srcAmp: [0, 1, \lin, 0, 0.5],

+

mu: [0, 15, \lin, 0, 3.6],

+

theta: [0.1, 7, \lin, 0, 1.9],

+

tMul: [1, 500, \lin, 0, 325],

+

amp: [0.0, 1, \db, 0, 0.5]

+

)

+

)).add;

+


+

\VanDerPol.sVarGui.gui

+

)

+


+

s.scope(2)

+


+ + diff --git a/Help/GFIS.html b/Help/GFIS.html new file mode 100755 index 0000000..9da61ac --- /dev/null +++ b/Help/GFIS.html @@ -0,0 +1,538 @@ + + + + + + + + + + + +

GFIS generalized functional iteration synthesis pseudo ugen

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

The GFIS class implements functional iteration synthesis as pseudo ugen loosely based on the description by Agostino Di Scipio ([1], [2]), who used the abbreviation FIS and pointed to its rich potential. Yari Marimoto has written a plugin implementation of the main sine-map iteration model, which is included in the trnsnd quark under the same name. The GFIS pseudo ugen implementation allows settings which go beyond functional iteration in a strict sense. 

+

Principle idea of synthesis: given a parametrized non-linear function, time-variance of init values and/or parameter sets with fixed iteration depth n can produce interesting waveforms. Due to the highly non-linear dynamics involved, a great amount of unpredictability invites to experiment and exploration – depending on the characteristics of the time-varying signal, results span from brittle noisy textures to drones with rich spectral movements. The cited papers mainly describe strict iteration with sine and mention iterated waveshaping, but as the GFIS class implementation just takes an arbitrary Function it's easy to blur the concept, e.g. by altering the Function and/or the parametrization depending on the iteration level and/or applying iteration on multichannel signals, crossing their data etc. Also interesting – and probably not widely explored - is the use of functional iteration as controller / modulator / engine for other synthesis methods.

+


+

WARNING: Be careful with amplitudes, in general higher numbers of iteration produce signals with more energy and due to the non-linear dynamics signals can suddenly become loud! Also go sure that your function doesn't allow blowup with iteration (this at least doesn't happen with the standard examples of the sine map model). 

+


+

[1] Di Scipio, Agostino (1999). "Synthesis Of Environmental Sound Textures by Iterated Nonlinear Functions" in: Proceedings of the 2nd COST G-6 Workshop on Digital Audio Effects (DAFx99), NTNU, Trondheim, December 9-11, 1999.

+

[2] Di Scipio, Agostino (2001). "Iterated Nonlinear Functions as a Sound-Generating Engine" Leonardo, Vol. 34, No. 3 (2001), pp. 249-254, MIT Press.

+


+

See also: Fb1

+


+

Creation / Class Methods

+


+

*ar (func, init, n = 1, nOut, leakDC = true, leakCoef = 0.995)

+

+

func - Function used to establish the iteration by applying it n times 

+

at build time of the synthdef graph. The Function should take two arguments: 

+

the signal and an optional index. It should return the signal used for iteration.

+

The signal can be multichannel, then the Function might take that into account

+

and refer to single channels of the signal arg - but the Function might also ignore 

+

it and rely on multichannel expansion, see examples.

+

Note that UGens written within func are instantiated n times, this is usually

+

not what you want for iterating the same parametrical function, with determined

+

signals it's a waste of CPU and for random UGens the result is different.

+

For the strict interpretation of FIS define the parameter signal outside and

+

refer to it from inside func.

+

init - Init value for the iteration, can also be a SequenceableCollection.

+

n - Integer, the maximum iteration number, it determines how often the Function

+

is used for building the synthdef graph, hence this value is not modulatable. 

+

nOut - Integer or SequenceableCollection of Integers.

+

An Integer determines the iteration level of the returned signal.

+

That way you can define a maximum iteration number n and switch between

+

lower ones, however n iterations are permanently calculated. 

+

In general switching will cause clicks, so this is an option for testing primarily.

+

A SequenceableCollection of level indices will produce a

+

multichannel signal, which in turn allows defining smooth transitions

+

between signals of different iteration levels.

+

leakDC - Boolean. Determines if a LeakDC is applied to the output.

+

If the parameter signal doesn't change (which can e.g. happen with a LFDNoise UGen) 

+

the result will in general be a DC offset, hence DC leaking is recommended.

+

Defaults to true.

+

leakCoef - Number, the leakDC coefficient. Defaults to 0.995.

+


+

*kr (func, init, n = 1, nOut, leakDC = true, leakCoef = 0.995)

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Examples 1) The sine map model

+

+

// These examples use an iterated sine map as described by Agostino Di Scipio.

+

// For the sine map sin(r * x) values of r varying between 2 and 4 are interesting.

+

// Driven by LFNoise parametrizations as in the first examples we get noise textures.

+


+


+

Ex.1a) Time-varying the factor r

+


+


+

(

+

y = {

+

var r = LFDNoise3.ar(10).range(3.5, 4);

+

GFIS.ar({ |x| sin(r * x) }, 0.3, 9) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+

// this is not "classical" FIS:

+

// for each iteration a different parametrization is taken !

+

// As LFDNoise UGens aren't coupled, pulsations are less unique

+


+

(

+

y = {

+

GFIS.ar({ |x| sin(LFDNoise3.ar(10).range(3.5, 4) * x) }, 0.3, 9) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+


+

// less iterations

+


+

(

+

y = {

+

var r = LFDNoise3.ar(10).range(3.5, 4);

+

GFIS.ar({ |x| sin(r * x) }, 0.3, 7) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+


+

// different init value

+


+

(

+

y = {

+

var r = LFDNoise3.ar(10).range(3.5, 4);

+

GFIS.ar({ |x| sin(r * x) }, 0.85, 7) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+


+

// higher iteration gives sections with more high frequencies in the spectrum

+

// even higher numbers soon lead to (interrupted) white noise

+


+

(

+

y = {

+

var r = LFDNoise3.ar(3).range(3.5, 4);

+

GFIS.ar({ |x| sin(r * x) }, 0.3, 12) * 0.03 ! 2

+

}.play

+

)

+


+

y.release

+


+


+

// higher iteration numbers can partially be "equilibrated" with lower r

+

// this leads to different sounds, here a more "airy" noise

+


+

(

+

y = {

+

var r = LFDNoise3.ar(7).range(2.9, 3.1);

+

GFIS.ar({ |x| sin(r * x) }, 0.3, 15) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+

// granular-like noise burst textures

+


+

(

+

y = {

+

var r = LFDNoise3.ar(50).range(2.5, 3);

+

GFIS.ar({ |x| sin(r * x) }, 0.3, 15) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+
Ex.1b) Time-varying init values

+


+

// mono

+


+

(

+

y = {

+

var i = LFDNoise3.ar(7).range(0.2, 0.9);

+

GFIS.ar({ |x| sin(3.2 * x) }, i, 10) * 0.1 ! 2

+

}.play

+

)

+


+

y.release

+


+


+

// stereo init is propagated to a stereo signal

+


+

(

+

y = {

+

var i = LFDNoise3.ar(7).range(0.2, 0.9) * [1, 1.01];

+

GFIS.ar({ |x| sin(3.2 * x) }, i, 10) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+

Ex.1c) Time-varying init values and factor r

+


+

(

+

y = {

+

var i = LFDNoise3.ar(7).range(0.2, 0.9) * [1, 1.01];

+

var r = LFDNoise3.ar(2).range(3.2, 3.6) * [1, 1.01];

+

GFIS.ar({ |x| sin(r * x) }, i, 9) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+

Ex.1d) Producing pitch by periodically oscillating parameters

+


+

// variants of phase glitter

+

// note that here again the "lazy" FIS with different oscillators per iteration is used

+


+

(

+

y = {

+

var osc = SinOsc.ar(30);

+

GFIS.ar({ |x| sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) }, [0.5, 0.505], 9) * 0.1

+

}.play

+

)

+


+

y.release

+


+

(

+

y = {

+

var osc = SinOsc.ar([30, 30.5]);

+

GFIS.ar({ |x| sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) }, 0.5, 9) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+

(

+

y = {

+

var osc = SinOsc.ar([30, 30.5]);

+

GFIS.ar({ |x| sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) }, [0.5, 0.505], 9) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+

// harmonics as different oscillation frequencies per iteration

+


+

(

+

y = {

+

var oscMod = SinOsc.ar(0.1).range(30.01, 30.3);

+

GFIS.ar({ |x, i| 

+

sin((SinOsc.ar([30, oscMod] * (i+1)) + LFDNoise3.ar(0.15)).linlin(-2, 2, 3, 4) * x) 

+

}, [0.5, 0.502], 7) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+


+

// Pulse as oscillator

+


+

(

+

y = {

+

var factors = Demand.ar(

+

TDuty.ar(Dxrand([4, 5, 7], inf)), 

+

0, 

+

Dseq([Dseq([1.3, 1.4], 2), 0.5], inf)

+

).lag(0.7);

+

var osc = Pulse.ar([70, 70 * factors]).lag(0.001);

+

LPF.ar(

+

GFIS.ar({ |x| 

+

sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) 

+

}, [0.5, 0.505], 9) * 0.1,

+

9000

+

)

+

}.play

+

)

+


+


+

y.release

+


+


+

Examples 2) The waveshaping model - iteration via buffered data

+


+


+

// a Buffer can be filled with an arbitrary mathematical function or audio data

+


+

// load audio

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+


+

// load to array

+


+

b.loadToFloatArray(action: { |array| a = array; "done".postln });

+


+


+

// take short snippet, normalize between 0 and 1

+

// that's most practical when we map to buffer index later on

+


+

// the sound of the snippet is quite irrelevant

+

// more oscillations in general produce more noise with iteration

+

// start trying with sine-like forms

+


+

d = a[3150..3300].normalize;

+


+

d.plot;

+


+


+

// fill new buffer for iteration

+


+

c = Buffer.loadCollection(s, d)

+


+


+


+

Ex.2a) Time-varying init values

+


+

// result of BufRd is used as index for the next BufRd

+

// needs Buffer c prepared above

+


+

(

+

y = {

+

GFIS.ar(

+

{ |x| BufRd.ar(1, c, c.numFrames * x) },

+

(LFDNoise3.ar(3) * [1, 1.1]).range(0.5, 0.51), 7

+

) * 0.2

+

}.play

+

)

+


+

y.release

+


+


+

Ex.2b) Time-varying index deviation

+


+

// needs Buffer c prepared above

+


+

(

+

y = {

+

var add = LFDNoise3.ar(0.3) * [0.05, 0.0505];

+

GFIS.ar(

+

{ |x| BufRd.ar(1, c, c.numFrames * (x + add)) }, 

+

0.5, 7

+

) * 0.2

+

}.play

+

)

+


+

y.release

+


+


+

Ex.2c) Time-varying init values and index deviation

+


+

// needs Buffer c prepared above

+


+

(

+

y = {

+

var add = LFDNoise3.ar(0.3) * [0.05, 0.0505];

+

GFIS.ar(

+

{ |x| BufRd.ar(1, c, c.numFrames * (x + add)) }, 

+

(LFDNoise3.ar(0.3) * [1, 1.01]).range(0.5, 0.505), 7

+

) * 0.2

+

}.play

+

)

+


+

y.release

+


+

Examples 3) GFIS as controller / modulator / engine for other synthesis

+


+

// this can transfer the instable characteristics to other sound worlds

+


+


+

Ex.3a) FM 

+


+

(

+

y = {

+

var mod = GFIS.ar({ |x| sin(LFDNoise3.ar(1).range(2.9, 4) * x) }, 0.3, 7);

+

SinOsc.ar(mod * [50, 51] * 70 + 300) * LFDNoise3.ar(2).range(0.2, 0.05)

+

}.play

+

)

+


+

y.release

+


+


+

Ex.3b) Buffer modulation phase controlled by GFIS 

+


+

p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";

+

b = Buffer.read(s, p);

+


+

(

+

y = {

+

var pos = 0.5; // other pos offset will give totally different sounds

+

var osc = GFIS.ar({ |x| sin(LFDNoise3.ar(10).range(3.2, 4) * x) }, 0.3, 6) * 0.1;

+

// GFIS involves a LeakDC, but not BufRd

+

LeakDC.ar(BufRd.ar(1, b, b.numFrames * (osc * [0.0120, 0.0125] * 5 + pos), interpolation: 4)) * 0.1

+

}.play

+

)

+


+

y.release

+


+


+

Ex.3c) Iterated GFIS 

+


+

// augmentation of non-linearity:

+

// GFIS itself used as time-varying control of another GFIS

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+


+

// load to array and fill new buffer for iteration

+


+

b.loadToFloatArray(action: { |array| a = array; "done".postln });

+


+

d = a[3150..3300].normalize;

+


+

c = Buffer.loadCollection(s, d);

+


+


+

(

+

y = {

+

var r = LFDNoise3.ar(3).range(2.7, 3.4);

+

var add = GFIS.ar({ |x| sin(r * x) }, 0.5, 3) * [0.05, 0.055];

+

GFIS.ar(

+

{ |x| BufRd.ar(1, c, c.numFrames * (x + add)) }, 

+

0.5, 7

+

) * 0.2

+

}.play

+

)

+


+

y.release

+


+


+

Ex.4) The nOut arg

+


+


+

// nOut allows for switching between iteration levels up to maximum n

+


+

(

+

y = {

+

|nOut = 10|

+

GFIS.ar({ |x| sin(LFDNoise1.ar(20).range(3, 3.5) * x) }, [0.2, 0.3], 10, nOut) * 0.1

+

}.play

+

)

+


+


+

y.set(\nOut, 9)

+


+

y.set(\nOut, 8)

+


+

y.release

+


+


+

// it can be passed an array of levels, 

+

// the resulting multichannel signal can e.g. be used for crossfaded switching with DXMix

+


+

// switch between 3 mono signals and double them

+


+

(

+

y = {

+

var src = GFIS.ar({ |x| sin(LFDNoise3.ar(30).range(3, 4) * x) }, 0.2, 9, [5, 7, 9]) * 0.1;

+

DXMix.ar(Dseq([0, 1, 2], inf), `src, fadeTime: 0.01, stepTime: 0.02, fadeMode: 1) ! 2

+

}.play

+

)

+


+

y.release;

+


+

// switch between 3 stereo signals

+


+

(

+

y = {

+

var src = GFIS.ar({ |x| sin(LFDNoise3.ar(30).range(3, 4) * x) }, [0.2, 0.21], 9, [5, 7, 9]) * 0.1;

+

DXMix.ar(Dseq([0, 1, 2], inf), `src, fadeTime: 0.01, stepTime: 0.02, fadeMode: 1)

+

}.play

+

)

+


+

y.release;

+


+


+
Ex.5) Comparison FIS / GFIS

+


+// FIS is contained in the trnsnd quark

+

// first example of its helpfile

+


+

{ FIS.ar(LinExp.ar(LFTri.ar(0.1), -1, 1, 1, 4), LFNoise2.ar(300).range(0, 1), 3, 0.1) }.play;

+


+

// the same with GFIS requires definition of varying params outside func 

+


+(

+

y = {

+

var r = LinExp.ar(LFTri.ar(0.1), -1, 1, 1, 4);

+

var i = LFNoise2.ar(300).range(0, 1);

+

GFIS.ar({ |x| sin(r * x) }, i, 3, 3, false) * 0.1

+

}.play

+

)

+


+

y.release

+


+

// proof of concept, difference is silent as it should

+


+

(

+

z = {

+

var r = LinExp.ar(LFTri.ar(0.1), -1, 1, 1, 4);

+

var i = LFNoise2.ar(300).range(0, 1);

+

GFIS.ar({ |x| sin(r * x) }, i, 3, 3, false) * 0.1 - FIS.ar(r, i, 3, 0.1)

+

}.play

+

)

+


+

z.release

+


+


+


+


+ + diff --git a/Help/HS with VarGui.html b/Help/HS with VarGui.html new file mode 100644 index 0000000..ffecf08 --- /dev/null +++ b/Help/HS with VarGui.html @@ -0,0 +1,388 @@ + + + + + + + + + + + +

HS with VarGui using HS / HSpar with VarGui 

+


+

Part of: miSCellaneous

+


+

See also: Working with HS and HSpar, VarGui, VarGui shortcut builds, Event patterns and LFOs, Event patterns and Functions

+


+


+

It is recommended to get familiar with the concepts of the HS / PHS and HSpar / PHSpar classes before combining them with VarGui, see Working with HS and HSpar for an overview. 

+

Alternative control setups with event patterns and VarGui examples are discussed in Event patterns and LFOs.

+


+


+

Differences to other control setups with event patterns and VarGui 

+


+

Instances of HS and PHS are hybrid objects in the sense that their functionality is not interchangeable with that of some (one might think at a first glance) related objects (Synths and Pbinds). A HS contains a SynthDef but will also hold Synths derived thereof. A PHS holds Pbind pairs but, when played, instantiates two EventStreamPlayers to be synchronized, also taking control over the used HS. A played PHSpar even controls a third player switching between running control synths. 

+


+

On the other hand VarGui is already prepared to accept synths / synth definitions and pbinds / eventstream players / tasks functions / tasks for generating synth and stream players. For plugging these concepts together it seems practical to use objects (resp. introduce adapting ones) that fit into what's already there. This can be achieved by two methods:

+


+

1.) .newPaused, applicable to PHS / PHSpar makes the used HS / HSpar generate a new paused Synth (or possibly several in case of PHSpar). Synths are returned by the method and can be passed to VarGui, which automatically detects their derivation from HS / HSpar and adapts gui functionality.

+


+

2.) .asTask, applicable to PHS / PHSpar and PHSuse / PHSparUse returns a wrapper Task for compound players of the PHS family. Playing and stopping the wrapper Task invokes playing and stopping behaviour of the underlying compound players, per default also taking control over playing and stopping the help synth(s).

+


+

An alternative approach to link HS and HSpar with VarGui is shown in Ex. 3.

+


+


+


+

Example 1a:   HS / PHS

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

(

+

h = HS(s, { |midiCenter = 70, dev = 20, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) });

+


+

p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) ]);

+


+

// Instantiation and return of a new paused Synth from HS's synth definition

+


+

x = p.newPaused;

+


+

// second intermediate object:

+

// PHS's asTask method generates a wrapping task

+

// which will invoke expected player actions by notification

+


+

// Note asTask's flag newEnvir, it determines if 

+

// the player should run in a newly generated environment, defaults to true.

+

// This allows to take one PHS definition with varibles to be set in

+

// different environments (as with Pbind). 

+


+

t = p.asTask;   

+


+

// also compare play / stop behaviour with these options (default was hsStop: false, hsPlay: true):

+

// hsPlay = false will run Synth together with stream only for the first time

+


+

// t = p.asTask(hsStop: true, hsPlay: true);

+

// t = p.asTask(hsStop: true, hsPlay: false);

+

// t = p.asTask(hsStop: false, hsPlay: false);

+

)

+


+

(

+

// VarGui detects that a Synth derived from a HS has been passed:

+

// synth player stop / reset button and mode buttons are greyed out,

+

// pause button background color is blue as Synth is new and paused.

+

// Playing and stopping the stream player will also cause the synth's running 

+

// (and stopping with asTask's option hsStop = true),

+

// however playing and stopping the help synth separately is still possible.

+


+

// For Synths derived from HS / HSpar pushing the general stop button will 

+

// only cause pausing - other synths will be freed - whereas Cmd. will free all synths,

+

// but ends HS gui control. Then a new VarGui would have to polled from reevaluated x and t. 

+


+

v = VarGui([], 

+

[[\midiCenter, [50, 65, \lin, 0.01, 60],

+

\dev, [0, 10, \lin, 0.01, 10],

+

\devFreq, [0, 3, \lin, 0.01, 0.5] ]],

+

t, x 

+

).gui;

+

)

+


+

// free resources, PHSplayer is wrapped, so use Cmd-. or this

+


+

h.free; 

+


+


+

Example 1b:   HS / PHS and PHSuse

+


+


+

(

+

h = HS(s, { |midiCenter = 70, dev = 20, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) });

+


+

p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) ]);

+

q = PHSuse(h, 0.3, [ \midinote, Pkey(\val) + 5 ]);

+

r = PHSuse(h, 0.4, [ \midinote, Pkey(\val) + 10 ]);

+


+

x = p.newPaused;

+


+

// quant arg for syncing

+


+

t = [p,q,r].collect(_.asTask(quant: 0.3));

+

)

+


+

(

+

// The PHSplayer has control over the help synth,

+

// PHSusePlayers can't be played before,

+

// though it's possible to start all players together with shift-click.

+


+

// For the same reason hsStop and hsPlay options are only available for the PHS-wrapping Task.

+


+

// After PHSplayer has been started (and maybe paused) PHSusePlayers can be

+

// played and stopped separately. 

+


+


+

v = VarGui([],

+

[[ \midiCenter, [50, 65, \lin, 0.01, 60],

+

\dev, [0, 10, \lin, 0.01, 10],

+

\devFreq, [0, 3, \lin, 0.01, 0.5] ]],

+

t, x 

+

).gui;

+

)

+


+

h.free; 

+


+


+

Example 2a:   HSpar / PHSpar

+


+


+

(

+

h = HSpar(s, [

+

{ |midiCenter = 65, dev = 10, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }, 

+

{ |midiCenter = 90, dev = 10, devFreq = 1| LFSaw.kr(devFreq, 0, dev, midiCenter) }

+

]);

+


+

// switching behaviour defined by hsIndices

+

+

p = PHSpar(h, 

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [-4, 5] ]],

+

hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf))  

+

]);

+

+

// for PHSpar this returns a collection of new paused help synths

+


+

x = p.newPaused;

+


+

t = p.asTask(quant: 0.3, hsStop: true);

+


+

// You can specify start and stop options for selected Synths of HSpar 

+

// with indices or collections of indices, e.g.:

+

// t = p.asTask(quant: 0.3, hsStop: 0);

+

)

+


+

(

+

// Playing and stopping the PHSparPlayer's wrapper Task affects both help synths in parallel.

+


+

v = VarGui([],

+

[[54.1, 3.85, 1.5], [60, 7.8, 2.7]].collect { |y| [ 

+

\midiCenter, [50, 65, \lin, 0.01, y[0]],

+

\dev, [0, 10, \lin, 0.01, y[1]],

+

\devFreq, [0, 3, \lin, 0.01, y[2]]]

+

}, t, x 

+

).gui;

+

)

+


+

h.free; 

+


+


+

Example 2b:   HSpar / PHSpar and PHSparUse

+


+


+

(

+

h = HSpar(s, [

+

{ |midiCenter = 65, dev = 10, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }, 

+

{ |midiCenter = 90, dev = 10, devFreq = 1| LFSaw.kr(devFreq, 0, dev, midiCenter) }

+

]);

+

+

p = PHSpar(h, 

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [-4, 5] ]],

+

hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf))  

+

]);

+


+

x = p.newPaused;

+


+

q = PHSparUse(h,  

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [0, 9] ]],

+

hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) ] 

+

);

+


+

r = PHSparUse(h,  

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [2.5, 7] ]],

+

hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) ] 

+

);

+


+

t = [p,q,r].collect(_.asTask(quant: 0.3));

+

)

+


+

(

+

v = VarGui([],

+

[60, 75].collect { |y| [  

+

\midiCenter, [55, 85, \lin, 0.01, y],

+

\dev, [0, 10, \lin, 0.01, 10],

+

\devFreq, [0, 3, \lin, 0.01, 0.5]]

+

},

+

t, x 

+

).gui;

+

)

+


+

h.free; 

+


+


+

Example 2c:   HSpar / PHSpar and PHSparUse with switch pattern

+


+


+

(

+

h = HSpar(s, [

+

{ |midiCenter = 65, dev = 10, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }, 

+

{ |midiCenter = 90, dev = 10, devFreq = 1| LFSaw.kr(devFreq, 0, dev, midiCenter) }

+

]);

+

+

+

// define event pattern to switch between the two help synths,

+

// switch times (average and random deviation) to be controlled from gui as well as

+

// chord structure determined by a single interval parameter 

+


+

p = PHSpar(h, 

+

switchDur: Pfunc { ~swTmMid * (1 + rand2(~swTmDev)) },

+

switchIndex: Pseq([0,1], inf),

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + Pfunc { [~int.neg, 0, ~int] } ]],

+

switchOn: true, // help synths to be resumed when active and ...

+

switchOff: true // ... to be paused when left - will be reflected by VarGui's button background colors

+

);

+

+

x = p.newPaused;

+


+

// chord structure of other pbinds will be taken from same variable ~int, so ...

+


+

q = PHSparUse(h, [ 0.15, [ \midinote, Pkey(\val) + Pfunc { ~int.neg / 3 + [~int.neg, 0, ~int] } ]]);

+

r = PHSparUse(h, [ 0.15, [ \midinote, Pkey(\val) + Pfunc { ~int * 3 / 5 + [~int.neg, 0, ~int] } ]]);

+


+

// ... players must be in the same environment, this is ensured by setting .asTask's flag newEnvir to false,

+

// all will be played and set in currentEnvironment.

+


+

t = [p,q,r].collect(_.asTask(quant: 0.3, newEnvir: false));

+

)

+


+

(

+

v = VarGui([

+

\swTmMid, [0.3, 1.5, \lin, 0.01, 1],

+

\swTmDev, [0, 0.5, \lin, 0.01, 0.5],

+

\int, [0, 12, \lin, 0.01, 8]

+

],

+

[60, 75].collect { |y| [  

+

\midiCenter, [55, 85, \lin, 0.01, y],

+

\dev, [0, 10, \lin, 0.01, 10],

+

\devFreq, [0, 3, \lin, 0.01, 0.5]]

+

},

+

t, x 

+

).gui;

+

)

+


+

// As can be seen in gui stopping with red stop button won't stop switching.

+

// Player had been started with asTask's default option switchStop = false

+

// and, as wrapped in a task, is not directly accessible.

+

// Anyway you can, as always, stop and free resources with Cmd-. or

+


+

h.free; 

+


+


+


+

Example 3:   Help Synths not passed explicitely

+


+


+

This is an alternative approach if syncing control synths and streams is not important - whereas resetting control synths becomes an option.

+


+

(

+

// Actual help synths can be defined separately and fed into

+

// formal help synths via control busses

+


+

// control synths hard-wired to allocated busses

+


+

c = Bus.control(s, 2).index;

+


+

SynthDef(\control_1, { |midiStart = 65, midiDiff = 15, duration = 10| 

+

Out.kr(c, XLine.kr(midiStart, midiStart + midiDiff, duration) ) }).add;

+

SynthDef(\control_2, { |midiStart = 90, midiDiff = 15, duration = 10| 

+

Out.kr(c+1, XLine.kr(midiStart, midiStart - midiDiff, duration) ) }).add;

+


+

h = HSpar(s, [{ In.kr(c) }, { In.kr(c+1) }] );

+


+

// PHSpar and PHSparUse defined in same way as above but ...

+

// ... PHSparPlayer wrapper Task defaults to hsStop = false,

+

// so reading values from bus c is not stopped with pausing and

+

// PHSparUsePlayers can still get new values from "external" control synths

+


+

p = PHSpar(h, 

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [-4, 5] ]],

+

hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf))  

+

]).asTask(quant: 0.3);

+


+


+

q = PHSparUse(h,  

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [0, 9] ]],

+

hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) ] 

+

).asTask(quant: 0.3);

+


+

r = PHSparUse(h,  

+

pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [2.5, 7] ]],

+

hsIndices: [ Pstutter(Prand([2,3,5, 11], inf), Pseq([0,1], inf)) ] 

+

).asTask(quant: 0.3);

+

)

+


+


+

(

+

// Now control synths have to be started before streams !

+

// Caps + shift click for parallel play action will work on cocoa, 

+

// you can choose custom bundle latency (c) and set it slightly below server latency

+


+

v = VarGui([],

+

[60, 80].collect { |x| [ 

+

\midiStart, [50, 95, \lin, 0.01, x],

+

\midiDiff, [0, 30, \lin, 0.01, 15],

+

\duration, [1, 20, \lin, 0.01, 15]]

+

}, [p,q,r], [\control_1, \control_2]

+

).gui(playerPriority: \synth, sliderPriority: \synth);

+


+

// modes of "external" control synths can be set

+

// resetting (starting new synths of same definition) is also possible

+

)

+


+

// additional synths engaged here, so cleanup with Cmd-. or stopping in gui plus ...

+


+

h.free;

+


+


+ + diff --git a/Help/HS.html b/Help/HS.html new file mode 100755 index 0000000..bfd8fbd --- /dev/null +++ b/Help/HS.html @@ -0,0 +1,277 @@ + + + + + + + + + + + +

HS (HelpSynth) object for use of synth values in the language by event patterns

+


+

Part of: miSCellaneous

+


+

Inherits from: Object

+


+

To be used in connection with PHS / PHSuse to play event patterns using synth values. Holds a singular synth definition, keeps track of OSC traffic when PHS / PHSuse are played. For using several help synths in parallel or setting controllers of a singular help synth see HSpar and related.

+


+

See also: Working with HS and HSpar, HS with VarGui, PHS, PHSuse, PHSplayer, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (server, ugenFunc, demandLatency, respondLatency, postOSC, granularity, inputCheck)

+

+

Creates a new HS object.

+

+

server - Must be running server.

+

ugenFunc - Function that defines the synth. 

+

demandLatency - Latency of help synth in seconds. Default value 0.15. 

+

respondLatency - Time in seconds, given to the response to be received by the client on time. 

+

Default value 0.15.

+

postOSC - Boolean for posting of (server to client) OSC messages. Defaults to false.

+

granularity - Time grains per second, quantization for bookkeeping. Defaults to 200.

+

inputCheck - Boolean for checking input data. Defaults to true.

+

+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// make a new HS 

+

// This compiles the SynthDef and prepares the HS to be played with a PHS,

+

// no Synth object is yet instantiated.

+

+

h = HS(s, { LFDNoise3.kr(0.7, 15, 75) });

+


+

// A PHS, like a Pbind, defines event stream behaviour, only durations are given separately.

+

// Here values are demanded just by one stream with constant duration, 

+

// but more than one duration pattern per HS and more than one Pbind per duration pattern

+

// may be defined - see the PHS help file for examples. 

+

// The play method of a PHS creates a PHSplayer which plays a synth from HS's synth definition, 

+

// synth values are accessible within the PHS definition by the variable ~val, e.g. by Pkey(\val).

+

// If HS's synthdef has no args, this must be specified in the PHS by nil or [].

+

+

p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) ]).play;

+

+

// also:

+

// p = PHS(h, [], 0.15, [ \midinote, Pfunc { |e| e.use { ~val } }  ]).play;

+

+

// stop allows resuming, cleanup with free or Cmd-. 

+

+

p.stop; // HS synth still playing 

+

+

p.play; // resume the PHSplayer

+

+

p.stop(true); // HS synth also paused 

+


+

p.play; // resume the PHSplayer together with HS synth

+

+

p.free; // also stop HS synth and cleanup - PHSplayer and HS object are freed

+


+


+

Accessing Instance Variables

+

+

demandLatency_(arg)

+

demandLatency

+

+

Latency of help synth in seconds. Defaults to 0.15. 

+

+

respondLatency_(arg)

+

respondLatency

+

+

Time (in seconds) given to the response to be received by the client on time. Defaults to 0.15.

+

+

postOSC_(arg)

+

postOSC

+

+

Defines whether OSC messages should be posted or not. Boolean. Defaults to false.

+

+

granularity_(arg)

+

granularity

+

+

Integer. Time grains per second, quantization for bookkeeping. Defaults to 200.

+


+

inputCheck_(arg)

+

inputCheck

+

+

Boolean for checking input data. Defaults to true.

+

+

+

Status control

+


+

listen(num, latency)

+

+

Make HS ready to poll values from a synth, demanded by possibly more than one stream. 

+

Therefore num trigger synths are run, ready to receive triggers for sending help synth values back to client,

+

but a synth from HS's ugenFunc definition is not yet playing after that.

+

If PHS / PHSuse are played there is no need to call listen explicitely.

+

+

play(args, latency)

+

+

Play a synth derived from HS's ugenFunc definition. HS must already be listening.

+

If PHS / PHSuse are played there is no need to call play explicitely.

+

+

clearBookkeeping

+

+

Cleanup OSC bookkeeping.

+

+

stop

+

+

Free the playing help synth and cleanup OSC bookkeeping.

+


+

sleep

+

+

Free the listening trigger synths.

+

+

busFree

+

+

Deallocate the bus.

+

+

free

+

+

Free all related PHSplayers / PHSusePlayers, then stop, sleep and busFree.

+


+


+

Note: stop and free will normally be done by the respective player methods, see PHSplayer.    

+

+

+

+

Examples

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// define a tendency for chord density

+


+

h = HS(s, { LFDNoise3.kr(0.5, 4, 5) });

+


+


+

// language operations used for building chords from synth values

+


+

(

+

p = PHS(h, [], 0.18, 

+

[\midinote, Pkey(\val).collect {|x| Array.series(x.round, 60 - (x * 1.2), 5) + Array.rand(x.round, -0.8, 0.8)  },

+

\legato, 0.6, \amp, 0.05]

+

).play;

+

)

+

+

// cleanup (freeing buses and nodes) by pressing Cmd-. or explicitely

+

+

p.free;

+


+


+

/////////////////////////////////////////////////////////////////////

+


+

// example with other than default instrument

+

// define synth to move between two sounds

+


+

(

+

SynthDef(\simpleMorph, {|out = 0, freq = 440, amp = 0.1, morphQ = 0|

+

var src, normalMorphQ = morphQ.mod(1);

+

src = Saw.ar(freq, mul: amp) * (1 - normalMorphQ) + (SinOsc.ar(freq, mul: amp) * normalMorphQ);

+

Out.ar(out, src ! 2 * EnvGen.ar(Env.perc, doneAction: 2));

+

}).add;

+

)

+


+

// HelpSynth definition, values between 0 and 1

+

// Clock and Quant for syncing

+


+

(

+

h = HS(s, { LFTri.kr(0.5, mul: 0.5, add: 0.5) });

+


+

c = TempoClock.new;

+

q = 0.2;

+

)

+


+

// help synth values for pitch and synth arg \morphQ 

+

 

+

(

+

p = PHS(h, [], 0.2, 

+

[\instrument, \simpleMorph, 

+

\midinote, Pkey(\val) * 30 + 60 + [0, 9] + Pxrand([0, 1.5, -1.5], inf), 

+

\amp, 0.07,

+

\morphQ, Pkey(\val) ]

+

).play(c,q);

+

)

+


+


+

// sync it with a normal pbind (EventStreamPlayer) with default instrument

+

// no use of HS / PHS

+


+

(

+

r = Pbind(

+

\dur, 0.2, 

+

\midinote, Pxrand([58, 60, 61, 63, 64, 67, 69, 70], inf) + [-7, 0, 5, 9] + Pseq([0.2, -0.2],inf), 

+

\amp, 0.03

+

).play(c, quant: q);

+

)

+


+

// pause and stop are synonym

+


+

p.pause;

+


+


+

// resume p in sync

+


+

p.play(c, q);

+


+


+

// stop and free

+


+

(

+

r.stop;

+

p.free;

+

)

+


+


+ + diff --git a/Help/HSpar.html b/Help/HSpar.html new file mode 100755 index 0000000..6e26a79 --- /dev/null +++ b/Help/HSpar.html @@ -0,0 +1,139 @@ + + + + + + + + + + + +

HSpar (HelpSynthPar) object for use of synth values in the language by event patterns

+


+

Part of: miSCellaneous

+


+

Inherits from: HS (HelpSynth)

+


+

To be used in connection with PHSpar / PHSparUse to play event patterns using synth values. Holds synth definitions, keeps track of OSC traffic when PHSpar / PHSparUse are played. For using a singular help synth see HS and related.

+


+

See also: Working with HS and HSpar, HS with VarGui, PHSpar, PHSparUse, PHSparPlayer, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (server, ugenFuncs, demandLatency, respondLatency, postOSC, granularity, inputCheck)

+

+

Creates a new HSpar object.

+

+

server - Must be running server.

+

ugenFuncs - Collection of functions that define the synths. 

+

demandLatency - Latency of help synths in seconds. Default value 0.15. 

+

respondLatency - Time in seconds, given to the response to be received by the client on time. Default value 0.15.

+

postOSC - Boolean for posting of (server to client) OSC messages. Defaults to false.

+

granularity - Time grains per second, quantization for bookkeeping. Defaults to 200.

+

inputCheck - Boolean for checking input data. Defaults to true.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// define a HSpar with two help synth definitions 

+

+

(

+

h = HSpar(s, [ { |freq = 1, dev = 10, center = 70|

+

LFDNoise3.kr(freq, dev, center) },

+

{ |freq = 1, dev = 5, center = 70, addFreq = 0.1, addDev = 5|

+

LFTri.kr(freq, 0, dev, center) + SinOsc.kr(addFreq, 0, addDev) } 

+

]);

+

)

+


+

// define a PHSpar to switch between these two

+

+

(

+

p = PHSpar(h, 

+

Pwhite(2.5, 3), // switch duration

+

Pseq([0,1],inf), // switch indices

+

// helpSynthArgs:  always default values for help synth #0, always set help synth #1

+

  [nil, [\freq, 1.2, \center, Pwhite(60, 80)] ], 

+

  // pbindArgs:  different from PHS, they have to be given as collection; ~val refers to current switch

+

  [0.1, [\midinote, Pkey(\val) + [0, 5], \legato, 0.2, \amp, [0.1, 0.07]]] 

+

).play;  

+

)

+

+

// stop and free HSpar by player

+

+

p.free;

+


+


+

+

/////////////////////////////////////////////////

+


+


+

// HSpar with only one help synth

+

+

h = HSpar(s, [ { |freq = 1, dev = 5, center = 65| LFDNoise3.kr(freq, dev, center) } ] );

+


+


+

// to be used for setting synth args

+

+

(

+

p = PHSpar(h,

+

Pwhite(0.15, 0.35, inf), // switch durations

+

0, // switch index

+

  [[\center, Pwhite(65, 80)]], // set args

+

  [0.1, [\midinote, Pkey(\val) + Pseq([[0,-7], -2],inf), \legato, 0.3, \amp, 0.05 ]]

+

  ).play           

+

)

+

+

// stop and free HSpar by player

+

+

p.free;

+


+


+ + diff --git a/Help/Idev suite.html b/Help/Idev suite.html new file mode 100755 index 0000000..3540be9 --- /dev/null +++ b/Help/Idev suite.html @@ -0,0 +1,49 @@ + + + + + + + + + + + +

Idev suite classes for number search with integer distance from a source, optionally avoiding repetitions within a span

+


+

Part of: miSCellaneous

+


+

See also: DIdev, PIdev, PLIdev

+


+

DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples.

+


+

The main musical idea of these classes is, that it's often unwanted to have certain characteristics repeated within a perceptional time window. This might apply to melodic lines as well as to rhythmic patterns or sequences of timbre and can be continued in the domain of microsound. The principle can easily be understood with pitches, therefore most examples are of this kind. 

+


+

In the following example integers are searched within the neighbourhood of a rounded sine source. The hi and lo deviation is constant (+/-5) and a lookBack value of 3 garantuees that there are no repetitions of integer values within a group of 4 (e.g. find a closest repetition within the last 5 points). In general lookback and deviations can be dynamic, the source doesn't need to be rounded and the comparison threshold for the repetition check can also be passed as a dynamic argument.

+


+


+


+

+


+


+


+

NOTE: It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples.

+


+

NOTE: In contrast to PIdev and PLIdev, DIdev needs to know maximum deviations (minLoDev, maxHiDev) beforehand. Together with maxLookBack they determine multichannel sizes, which might be CPU-consuming. 

+


+


+ + diff --git a/Help/Introduction to miSCellaneous.html b/Help/Introduction to miSCellaneous.html new file mode 100755 index 0000000..6cbc0f9 --- /dev/null +++ b/Help/Introduction to miSCellaneous.html @@ -0,0 +1,589 @@ + + + + + + + + + + + +

Introduction to miSCellaneous overview, references and examples

+


+

Part of: miSCellaneous

+


+

At the beginning of 2017, it was almost 10 years ago when I did my first steps in systematically ordering and extending personal SC tools. At that time I already had some experience in SC, but project-oriented composition was my main focus. Meanwhile miSCellaneous lib has grown and when I look at its readme file, although I always tried to keep stuff documented properly, I doubt that the connections between the different classes would be easy to get at a first glance. Topics accumulated, some help files have become huge (VarGui, PbindFx) and a lot of examples and documented (extra-)features might hide the basic motivations. As I was asked by colleagues at the Institute of Electronic Music and Acoustic Graz (IEM) we organized a one-day lecture/workshop on miSCellaneous lib on November 5th, 2016, and this tutorial summarizes the overview given then. At that point I'd like to say that I'm very grateful to IEM Graz and the interested SC community from here and abroad for support and feedback, we are going to have further SC meetings at the same place – Hanns Holger Rutz already continued in December. There's also a focus on artistic research here at IEM, and research projects, events and discussions are lighting an ongoing discourse in the field between art and science, creating an inspiring environment.

+

Concerning the structure of this file: after a brief history and a grouping of content the tour will guide through selected topics in an order which, hopefully, will outline the central ideas. It will start with VarGui, PLx, then go over PbindFx, EventShortcuts to live coding aspects of PLx, continue with independent classes, class families, methods and SC tutorials and end with the Buffer Granulation tutorial, which again integrates some of the previous topics. PbindFx gets more space, as it's in my recent focus and you can use it for a number of things which are not, or at least not easily doable in plain SC. To a large extent the tour consists of references to selected already existing examples, which are spread over various help files. Conitinuative, but less central topics are marked as such, as well as some legacy code, which is still working, but not very relevant, as other possibilities have been invented meanwhile. A few new examples have been added, the reader is invited to check the exercises and to have fun with his/her favourite instrument resp. effect SynthDefs. 

+


+

History

+


+

In 2007 / 08 I was working at ZKM Karlsruhe, preparing a piece for flute and multichannel electronics (Lokale Orbits / Solo 3). Then I thought it would be useful to order and document my tools, by doing so my programming would – hopefully – not only be useful for me but for others too and I would be able to give something back to the open source community, from which I have been getting so much valuable input. Also I noticed that a better structuring of code together with the need of documentation stimulated reflection and development and significantly improved the functionality of my tools also just for personal use. 

+

Lokale Orbits is a series of works for small instrumentations and multichannel tape where recordings with involved musicians were the base for granular processings. From the beginning miSCellaneous lib was developed in parallel to the needs that came from that artistic motivation. The first particular motivation was related to the fundamental architecture of SC – the division between language and server – and its consequences for granular synthesis. I never wanted to spend much time in gui programming, but I wanted to have a multi-purpose gui that would easily let me experiment with granular synthesis driven by language (patterns in particular) and server (granulation ugens). It should also be easy to combine these different controls in a single patch, e.g. fine-tune the parameters of a LFO and those of a Pattern resp. the derived running EventStreamPlayer at the same time. This need led to the development of the VarGui interface. It is the the oldest part and, so to speak, the kernel of miSCellaneous, already contained in the first public release of 2009. A player section and a number of features was added in 2011. Thus VarGui doesn't use SC's extended gui features which came up with Qt and if I had to build something from scratch I'd certainly look for a revised code structure, nevertheless VarGui reliably served my needs quite well over a long period of time. The twofold control option (environmental variables and synth args) turned out to be useful in many contexts, also the handling of arrays (environmental variables as well as synth args) is quite practical and allows a quick instantiation of huge slider+player guis. 

+

Between 2009 and 2016 a number of pattern families was added, some of them with granular synthesis in mind. The one I'm using most is the PLx proxy pattern family which takes advantage of environmental variables and dynamic scoping and goes well together with the VarGui interface concerning control of running Patterns/EventStreamPlayers. PLx also opens nice opportunities for live-coding with very condensed syntax. I'm not doing this on stage but I see live-coding as valuable part of a dynamic compositional process. As a side remark, PLx patterns mirror most of SC's main lib patterns and can also be used as non-proxies. In contrast to main lib's list patterns they default to repeats = inf, which probably saved myself the typing of many thousands of 'infs' over the years.

+

Another part of miSCellaneous is a number of tutorials, which I added from time to time. Some refer to general SC topics, independent from miSCellaneous (e.g. Event patterns and array args), others to topics specific to miSCellaneous (e.g. PLx and live coding with Strings) and in some I tried a general overview of principal SC strategies, but also used examples with features of miSCellaneous (Buffer Granulation). Finally there's other stuff that doesn't fall into the above categories, e.g. the class EventShortcuts for customized shortcuts with Events and event patterns. Classes related to nonlinear dynamics (single sample feedback with Fb1, generalized functional iteration synthesis with GFIS) have been added in 2018, Fb1_ODE and related, a framework for general ordinary differential equation integration of initial value problems in 2019.

+


+


+


+

Groups of content

+


+

.) VarGui (2009), multi-purpose slider / player gui. Can have sliders for control of synth parameters and 

+

environmental variables as well as a player section for control of Synths, Tasks or 

+

EventStreamPlayers derived from Patterns.

+


+


+

.) Pattern classes/class families:

+


+

.) PHSx (2009): pattern-like objects using synth values in language,

+

still working but a bit outdated as we have synchronous buses now

+

+

.) PLx (2012): dynamic scope proxy patterns,

+

especially suited for VarGui control, also live coding

+

+

.) PSx (2014): patterns acting like streams and remembering last values,

+

good for certain types of nested pattern use and recursion

+

+

.) PmonoPar, PpolyPar (2015): differently timed setting of event streams

+

+

.) PbindFx (2015): sequencing arbitrary effects and effect graphs

+

+

.) PLbindef, PLbindefPar (2016): proxies based on Pbindef

+

allowing shortcut replacement syntax

+

+

.) PSVx (2016): a pattern implementation of Xenakis sieves related to the class Sieve,

+

Psieve patterns enable an unusual "realtime sieve modification".

+

Interesting for many applications, e.g. granular rhythms, 

+

though I didn't have the time to experiment a lot yet.

+

+

.) PSPdiv (2017): a dynamic multi-layer pulse divider based on Pspawner

+

+

.) Other pattern classes

+

+

+

.) Tutorials:

+


+

.) Event patterns and Functions (2011)

+


+

.) Event patterns and LFOs (2011)

+


+

.) Buffer Granulation Tutorial (2012)

+

different strategies of buffer granulation and control

+

+

.) Event patterns and array args (2015)

+


+

.) PLx and live coding with Strings (2016)

+


+

.) Sieves and Psieve patterns (2016)

+


+

.) kitchen studies (2016)

+

commented source code of six short pieces from a kitchen sound using PbindFx

+


+

.) Live Granulation Tutorial (2017)

+

different strategies of live granulation and control

+

+

.) Other tutorials

+

+


+

.) Other topics:

+


+

.) enum (2013): general enumeration tool

+


+

.) EventShortcuts (2014): user-defined keywords for events and event patterns

+


+

.) Smooth Clipping and Folding (2017)

+


+

.) DX suite (2017): pseudo ugens for crossfaded mixing and fanning with drate control

+


+

.) Idev suite (2018): patterns and drate ugen searching for numbers with integer distance from a source pattern / signal

+


+

.) Fb1, GFIS (2018): single sample feedback and generalized functional iteration synthesis

+


+

.) Fb1_ODE (2019): general ordinary differential equation integration

+


+

.) ZeroXBufWr / ZeroXBufRd / TZeroXBufRd (2020): playing sequences of segments between zero crossings with demand rate control

+


+

.) Other

+


+


+

Tour 1 – VarGui

+


+

The VarGui class help file as well VarGui shortcut builds are both bloated with information, so I'd like to give just a few examples and references here in order to show its basic features.

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

Tour 1a: synth control

+


+

// quick control of default synth, specs are globally known

+

// note that amp is set to 0 by its default spec

+

// start by pressing the green button

+


+

VarGui(synth: \default).gui

+


+


+

// alternative writing, see help file VarGui shortcut builds 

+


+

\default.sVarGui.gui     

+


+


+

For basic control of a self-defined Synth/SynthDef by passing control specs see the example "synth definition with raising frequency" in VarGui.

+


+

For control of multiple Synths/SynthDefs see the example in the section "discussion" of the same file below.

+


+

It's often more practical to pass control specs as SynthDef metadata as done in Ex. 1a of Buffer Granulation 

+


+


+

Exercise 

+


+

Control your own (sustained) SynthDef with VarGui, either use SynthDef metadata or VarGui's argument 'synthCtr' for passing specs. 

+


+


+

Tour 1b: environmental variables and pattern control

+


+

For basic control of an environmental variable in combination with a Pbind run the example in the discussion section of VarGui's method 'new'.

+


+


+

// after having evaluated p, consider the subtle differences of these variants:

+

// play with slider values and start and pause ad libitum.

+

// The quant argument ensures synchronization when starting players separately.

+


+

// one array variable in one environment, one player

+

v = VarGui([\midi, [50, 70, \lin, 1, 55] ! 3], stream: p, quant: 0.2).gui;

+


+

// three single variables in three environments, three players

+

v = VarGui([\midi, [50, 70, \lin, 1, 55]] ! 3, stream: p!3, quant: 0.2).gui;

+


+

// three array variables in three environments, three players

+

v = VarGui([\midi, [50, 70, \lin, 1, 55] ! 3] ! 3, stream: p!3, quant: 0.2).gui;

+


+


+

These examples show the application of dynamic scoping. A Function has been defined with an "unconnected" free variable and the players evaluate the Function in different Environments provided by the VarGui. Setting the sliders affects the variable of the same name in different Environments of different players.

+


+

This example used a Pfunc, but it works the same with PLx patterns, we take a look at them and leave VarGui for a moment.

+


+


+

Tour 2: PLx suite

+


+

Pdef and Pdefn are main lib's proxies for replacement of event patterns and non-event patterns. PL is the most general PLx proxy, taking over some combined functionality of Pdef and Pdefn on the base of dynamic scoping, go through the examples of the help file PL to see how it works with value and event patterns. 

+


+

Though what neither PL nor Pdef/Pdefn can provide is the replacement of pure lists or list items in the case of list patterns. There's a main lib workaround with a combination of Pn and Plazy (PLx suite, Ex. 1a), but it isn't satisfying for several reasons, so I suppose that PLx list patterns like PLseq are amongst the most useful ones of the whole PLx family, e.g. see PLx suite, Ex. 1b. Other PLx list patterns like PLrand, PLwrand, PLser, PLshuf, PLshufn, PLswitch etc. work similar.

+


+

There exists also a number of non-list PLx patterns, have a look at PLwhite as a typical example.

+

  

+

 

+

Exercise 

+


+

Play your own enveloped SynthDef (or take default SynthDef with params: freq, amp, pan) with some PLx patterns and perform live replacements as in the examples above.

+


+


+

Tour 3: PLx patterns used with VarGui

+


+

See VarGui, Ex. 1a, for basic step sequencing with PLseq, the array variable is implicitely defined in VarGui's first arg.

+


+

See VarGui, Ex. 1c for multiple players and array variables and control of multiple sliders and buttons with modifier keys (note that not all functionality might be available on all platforms).

+


+

See VarGui, Ex. 4a, for a sequencing setup with some PLs used. But more interesting here is that each synth reads is base frequency from a control bus, which gets its data from a separate synth. Synth and EventStreamPlayer are both controlled from the gui. The two slider blocks on the left side concern Synth settings (above) and variable setting for the Pbind / EventStreamPlayer (below). Accordingly we have two players on the right side. Try running the player and starting and stopping the control synth.

+

 

+

Buffer Granulation, Ex. 2a, shows basic language-driven granulation, gui values are taken over by PL patterns and Pfunc.

+

 

+

 

+

Exercise 

+


+

Write a combination of an event pattern and PLx patterns as above with your own SynthDef and play it with a VarGui. Note that it's not necessary to control all args by the gui, nor is it necessary to control parameters directly: you can e.g. control bounds for midinotes in the gui and define the calculation for the actual midinote (e.g. random selection) in the event pattern:

+


+

\midinote, PLwhite(\midiLo, \midiHi)

+


+


+

Tour 4: PbindFx

+


+

PbindFx is an event pattern for effect handling on per-event base. There are other ways for working with event patterns and effects, already possible with main lib, but they have disadvantages: with Pfx and Pfxb there is no built-in way to sequence effect types or effect parameters, you could also route the event's audio to effect buses, but for overlapping events with different fx graphs/params you'd have to define additional buses beforehand as in Ex. 4a.

+


+


+

Ex. 4a: sequencing fx params by using different fx buses

+


+

// first go to PbindFx, Ex. 1a, reboot server with extended ressources and evaluate source and fx synths.

+


+

// start fxs 

+

(

+

a = Bus.audio(s, 2);

+

b = Bus.audio(s, 2);

+


+

x = Synth(\echo, [decayTime: 1.5, echoDelta: 0.15, in: a]);

+

y = Synth(\echo, [decayTime: 5, echoDelta: 0.1, in: b]);

+

)

+


+

// play pattern, the two effects allow switching between them

+

(

+

p = Pbind(

+

\dur, 0.5,

+

\instrument, \source,

+

\note, Pshuf((0..11), inf) + Pseq([[0.2, 14.2], [0, 4], [0, 4]], inf),

+

\octave, Pwhite(3, 6),

+

\out, Pseq([b, a, a], inf)  // here we do fx sequencing

+

).play

+

)

+


+

p.stop

+


+

// we need to do cleanup manually here

+


+

[x, y, a, b].do(_.free);

+


+


+

Ex. 4b: sequencing fx params by using PbindFx

+


+

// Ex. 4a translated to PbindFx syntax –

+

// though it's not exactly identical as fxs are processed in not only two but

+

// more parallel fx synths

+


+

(

+

p = PbindFx([

+

\dur, 0.5,

+

\instrument, \source,

+

\note, PLshuf((0..11)) + PLseq([[0.2, 14.2], [0, 4], [0, 4]]),

+

\octave, Pwhite(3, 6),

+

\fxOrder, 1 // always fx #1 (echo)

+

],[

+

\fx, \echo,

+

\decayTime, PLseq([5, 1.5, 1.5]),

+

\echoDelta, PLseq([0.1, 0.15, 0.15]),

+

\cleanupDelay, 5.2,    // with short default echo would be cut

+


+

// this would save a bit CPU

+

// \cleanupDelay, PLseq([5, 1.5, 1.5]) + 0.2

+

]

+

).play

+

)

+


+


+

// cleanup (delayed freeing of synths and buses) is done automatically

+

// watch server window:

+


+

p.stop

+


+


+

// now run the same example with the following variant of 'echoDelta',

+

// obviously the result cannot be achieved with an approach like in Ex. 4a

+


+

\echoDelta, Pwhite(0.05, 0.2)

+


+


+


+

Ex. 4c: alternation of fx / non-fx by defining a fxOrder sequence

+


+

(

+

p = PbindFx([

+

\dur, 0.2,

+

\instrument, \source,

+

\note, PLshuf((0..11)) + PLseq([[0.4, 14.4], [0, 4], [0, 4]]),

+

\octave, Pwhite(3, 6),

+


+

// fxOrder = 0 means no fx

+

\fxOrder,  PLseq([0, 0, 1]),

+


+

// if no fx, we need to compensate the unified echo delay of 0.2

+

\lag, Pif(Pkey(\fxOrder) > 0, 0, 0.2)

+

],[

+

\fx, \echo,

+

\decayTime, PLseq([5, 1.5, 1.5]),

+

\echoDelta, Pwhite(0.04, 0.12),

+

\cleanupDelay, PLseq([5, 1.5, 1.5]) + 0.2

+

]

+

).play

+

)

+


+

p.stop

+


+


+

Exercise 

+


+

Play your own (percussive + stereo) SynthDef (or instrument 'source') with an arbitrary sequencing of no fx and echos (by defining 'fxOrder') and echo params as in Ex. 4c. Note that in fx 'echo' the max echoDelta defaults to 0.2.

+


+


+

Tour 4d: principle of operation

+


+

For each event several issues have to be internally considered by PbindFx: building and checking of fx graphs (no cycles !), cleaning buses from possibly remaining residual audio (adding "zero synths"), splitting (in case of parallel parts in the fx graph), grouping of all event-related synths and checking accumulated cleanup delay times. You might skip that for the moment, but for a more detailled overview see PbindFx, as well as for a listing of conventions.

+


+


+

Tour 4e: sequential application of fxs (fixed fx chains)

+


+

See PbindFx, examples 1a and 1b.

+


+


+


+

Tour 4f: sequencing different fx chains

+


+

See PbindFx, examples 2a-d.

+


+

Exercise 

+


+

Play your own (percussive + stereo) SynthDef (or instrument 'source') with an arbitrary sequencing of fx chains (your fxs and/or fxs from PbindFx help). Maybe just extend your last own example.

+


+


+

Tour 4g: parallel effects and arbitrary effect graphs

+


+

It seems to be a still underestimated option to design effect graphs different from simple chains. In a classical DAW interface a pile of slots for effects in chain is common, although more differentiated possibilities are also there. Considering event sequencing with PbindFx we can select fx graphs per event / grain, in addition to the sequencing of fx parameters itself. See PbindFx, Ex. 10a for a parallel application of echo, note the syntax of the event graph, passed as Event to 'fxOrder'.

+


+

Exercise 

+


+

Compare the sound of the two fx graphs given in Ex. 10a, also try the following or similar, how do the corresponding fx graphs look like ?

+


+

\fxOrder, `(0: 1, 1: [2, 3], 2: 4),

+

+

\fxOrder, `(0: 1, 1: [2, 3, \o], 2: 4),

+


+

\fxOrder, `(0: 1, 1: [2, 3], 3: 4, 2: 3),

+

+

\fxOrder, `(0: 1, 1: [2, 3], 3: 2, 2: 4),

+


+

\fxOrder, `(0: 1, 1: [2, 3, \o], 3: 4, 2: 3),

+


+


+


+

See PbindFx, Ex. 10b and 10c for modulation graphs and their sequencing.

+


+


+

Exercise 

+


+

Play your own (percussive + stereo) SynthDef (or instrument 'source') with an arbitrary sequencing of fx *graphs* (your fxs and/or fxs from PbindFx help). Maybe just extend your last own example.

+


+


+

Tour 4h: implicit parallelism of single effects

+


+

This can simple be done by passing arrays within fxData, see PbindFx, Ex. 4a. 

+


+


+

Tour 4i: different effects with parallel PbindFxs

+


+

A further option for parallelism, a typical case would be the application of different effects to the notes of a chord, see PbindFx, Ex. 3b (rather straight than 3a). 

+


+


+

Tour 4j: PbindFx and replacements

+


+

See PbindFx, Ex. 7a for replacement of key streams.

+


+

Up to now PbindFx got lists as args in all examples. As args can be event patterns too, they can also be proxy patterns which opens the door for various unusual kinds of source and fx replacements, see PbindFx, Ex. 7b and 7c.

+


+


+

Exercise 

+


+

Take one of your previous working PbindFx examples and rewrite its args (arrays of key/value pairs) as PL or Pbindef proxies. Run the example and replace source and/or fx patterns on the fly.

+


+


+

Tour 4k: continuative topics

+


+

For use with VarGui see PbindFx, Ex. 8.

+


+

For using one fx SynthDef in more than one fxData see PbindFx, Ex. 4.

+


+

For source and fxs reading from external buses (ar or kr) see PbindFx, Ex. 6a-c.

+


+

For using value conversions with fxData see PbindFx, Ex. 9.

+


+


+

Tour 4l: kitchen studies, a granular synthesis application

+


+

One motivation for the development of PbindFx was the idea to explore granular synthesis variants with differentiated effect processings. The fixed media composition kitchen studies collects six short pieces with different fxs and handlings of fx sequencing, each derived from the kitchen sound of five seconds, which is already contained in miSCellaneous lib. At the same time kitchen studies is an ongoing artistic research project: the commented source code is published in the tutorial kitchen studies, compressed versions of the original piece as a whole and its parts can be found on my website http://daniel-mayer.at, a further documentation of the compositional process will follow as publication in the artistic research database Research Catalogue (http://researchcatalogue.net).

+


+


+

Tour 5: EventShortcuts: less typing with Events and event patterns

+


+

EventShortcuts is an interface for defining your own shortcut keys for often used keyword in Events and event patterns. For example you might want to write 'inst' or just 'i' instead of 'instrument' etc., then define your collection of shortcuts – e.g. in your startup or a certain load file – and activate it on occasion. There is also a default shortcuts dictionary, see its content and play a simple example:

+


+


+

EventShortcuts.on;

+


+

EventShortcuts.postAll;

+


+

x = Pbind(\m, Pwhite(60, 90), \d, 0.2).play;

+


+


+

For examples of (re-)defining or extending shortcut dictionaries see EventShortcuts.

+


+

Exercise 

+


+

Take one of your favourite SynthDefs with non-standard arguments (other than freq, amp, pan, etc.) and write an event pattern example, using these arguments. Then choose useful abbreviations, define a new shortcut dictionary with these (either by extending the default or by defining a new one), make it current and run the event pattern example with abbreviated keys. 

+


+


+

Tour 6: live coding

+


+

This was not my main focus from the beginning, but it turned out that PLx patterns, in combination with EventShortcuts and/or Character sequencing (tour 6b) open up live coding possibilities with very condensed syntax.

+


+


+

Tour 6a: PLbindef and PLbindefPar

+


+

PLbindef is a wrapper class for Pbindef, which allows replacements in pseudo-method syntax in a newly created Environment.

+


+

EventShortcuts.on;

+


+

y = PLbindef(\x, \d, 0.2, \m, Pwhite(60, 90)).play;

+


+

// now 'x' is also the name of a new Environment in the current Environment,

+

// its pseudo-methods can be used for setting

+


+

~x.m = PLseq((60..70))

+


+

y.stop

+


+

For further examples see PLbindef.

+


+

PLbindefPar is also based on Pbindef, but unlike PLbindef it's not a plain wrapper: it employs a number of Pbindefs in parallel, which allows control of polyphonic, additive or granular structures, see PLbindefPar. WARNING: if you're piling up a lot of layers, be careful with amplitudes, the amplitude values are taken for the single layers, so you'd have to reduce them accordingly !

+

 

+


+

Tour 6b: PLx and live coding with Strings

+


+

Already in plain SC Strings as Arrays of Characters can be used for sequencing. PLx patterns fit and continuate this concept, see PLx and live coding with Strings for some options, also in connection with PLbindef, PLbindefPar and PbindFx.

+


+


+

Tour 7: independent classes, class families and methods

+


+

Tour 7a: PSx stream patterns

+


+

These are a bit paradoxical classes: Patterns which behave as if they were Streams, thus have an internal state and remember its last value(s), which can e.g. be used for recursion or certain demands of repeated embedding as in the following example:

+


+

(

+

// PS gets source and length patterns as args

+


+

p = PLseq([

+

PS(PLseq((1..5)), PLseq([1, 2])),

+

PS(PLseq((1..5) * 100), PLrand((3..5)))

+

]);

+


+

p.asStream.nextN(100)

+

)

+


+

// this can also be written with a combination of Streams and Patterns,

+

// but it needs more typing (same with Pswitch1 variants)

+


+

(

+

a = Pseq((1..5), inf).asStream;

+

b = Pseq((1..5) * 100, inf).asStream;

+


+

p = Pseq([

+

Pfuncn({ a.next }, Pseq([1, 2], inf).asStream), 

+

Pfuncn({ b.next }, Prand((3..5), inf).asStream),

+

], inf);

+


+

p.asStream.nextN(100)

+

)

+


+

See PSx stream patterns for an overview.

+


+


+

Tour 7b: PSVx sieve patterns and Sieves

+


+

Sieves, recommended by Iannis Xenakis as generative principles for arbitrary musical parameters, are implemented twice: with the class Sieve and Psieve patterns, which adapt the sieve calculus for realtime interactions. The tutorial Sieves and Psieve patterns starts from scratch, thus can be studied completely independent from other miSCellaneous stuff and most other SC requirements. The last chapter gives some audio examples, granular rhythms might be an especially interesting application.

+


+


+

Tour 7c: PmonoPar and PpolyPar

+


+

PmonoPar follows the Pmono convention of a single synth, being set but extends it to an arbitrary number of differently timed setting streams. With PpolyPar the number of continously running synths is arbitrary as well and setting streams can switch the synths to set. That way complicated fx variations can be achieved by a paradigm different from PbindFx.

+


+


+

Tour 7d: enum

+


+

A general tool, which can be used for many enumeration and optimization problems (sets, partitions, graphs etc.), melodic shapes and scales are possible musical applications, see enum.

+


+


+

Tour 7e: HS / HSpar / PHS / PHSpar

+


+

A framework for using server-generated values in Pbind-like objects in the language. A bit outdated now, as synchronous bus gives easy access to server values, however the double-latency mechanism provides a good accuracy of values – better than synchronous bus with standard hardware settings if this is needed – by passing a high granularity parameter. A lower value minimizes OSC traffic if this is more important. See Working with HS and HSpar.

+


+


+

Tour 7f: PSPdiv

+


+

A dynamic multi-layer pulse divider based on Pspawner, as the latter it supports parallel and sequential sprouting of sub-patterns. Might be used for line ornamentation, polyrhythmical structures, granulation etc., see PSPdiv.

+


+


+

Tour 7g: Smooth Clipping and Folding

+


+

A suite of pseudo ugens, see Smooth Clipping and Folding.

+


+


+

Tour 7h: DX suite

+


+

pseudo ugens for crossfaded mixing and fanning according to demand-rate control, see DX suite.

+


+


+

Tour 7i: Idev suite

+


+

patterns and drate ugen searching for numbers with integer distance from a source pattern / signal, see Idev suite.

+


+


+

Tour 7j: Nonlinear dynamics

+


+

pseudo ugens for single sample feedback and generalized functional iteration synthesis, see Fb1 and GFIS. 

+

General ordinary differential equation integration, see Fb1_ODE and related classes.

+


+

Tour 7k: ZeroXBufWr / ZeroXBufRd / TZeroXBufRd

+


+

pseudo ugens for zero crossing analysis and playing sequences of segments between them with demand rate control, see ZeroXBufWr, ZeroXBufRd, TZeroXBufRd.

+


+


+


+

Tour 8: (Rather) independent SC tutorials

+


+

Tour 8a: Event patterns and Functions

+


+

This tutorial is about dynamic scope, comparing the behaviour of Functions, Streams and EventStreamPlayers in Environments. It's thus treating some preconditions which are relevant for PLx suite and VarGui, see Event patterns and Functions.

+


+


+

Tour 8b: Event patterns and LFOs

+


+

Continuous (with LFO) and discrete ("LFO-like") control strategies for event patterns are compared in Event patterns and LFOs.

+


+


+

Tour 8c: Event patterns and array args

+


+

SynthDef array args seem to be a sometimes confusing topic, especially when it's about (pseudo-)variable array lengths and Envelopes, this is even more the case when it comes to the sequencing of such synths. For this reason, and not at last to remind myself to the subtle syntax differences, I wrote this tutorial: Event patterns and array args.

+


+


+

Tour 9: Buffer Granulation and Live Granulation – tutorials

+


+

Actually scheduled as a general overview of granulation possibilities in SC, also collecting various ideas from the sc-users mailing list discussions, I have to admit that in its current form many examples, especially in the Buffer granulation tutorial, require one or more features of miSCellaneous and thus might not always be easy to follow. Then again it would be hard to write such (gui) examples without presuppositions and at the same time with a clearly representable amount of code. However I hope that based on this guided tour it might be easier to step through for people who haven't used this lib before, see Buffer Granulation and Live Granulation.

+


+


+ + diff --git a/Help/Live Granulation.html b/Help/Live Granulation.html new file mode 100755 index 0000000..e332eb4 --- /dev/null +++ b/Help/Live Granulation.html @@ -0,0 +1,938 @@ + + + + + + + + + + + +

Live Granulation different approaches to live granulation with gui examples 

+


+

Part of: miSCellaneous

+


+

See also: Buffer Granulation, Introduction to miSCellaneous, VarGui, VarGui shortcut builds, PLx suite, PbindFx, kitchen studies, Sieves and Psieve patterns, PSPdiv, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+


+

This file is a complement to the Buffer Granulation tutorial. It contains variants of granulation that are applied to an audio signal directly, without the explicit use of a buffer. As with buffer granulation there exist language-driven and server-driven as well as hybrid variants. Especially pattern-based live granulation raises certain accuracy issues, which are summarized in this tutorial. 

+


+

WARNING: 

+


+

1.) Be careful with amplitudes ! 

+

To reduce feedback I've built in tanh, LPF and delay into examples with SoundIn, 

+

though better use headphones to avoid feedback at all. 

+

For tips on reducing feedback or creative use of feedback see Nathaniel Virgo's Feedback quark.

+

+

2.) Avoid too early freeing of audio buses:

+

a) When there are still running synths, unintendedly sound might be routed to a processing resp. feedback chain.

+

b) For the same reason don't free buses if they are hard-wired to SynthDefs, you still want to use.

+

You can free buses on oaccasion if you are sure that nothing is running and you won't need them again.

+

Keep in mind that you can also (re-)start the server with a higher number of audio buses available (Ex. 2c)

+

+

3.) I haven't used below setups for live performances. Although all of them work stable for me as they are, in general hangs can occasionally happen with pattern-driven setups. Often this can be tracked down to sequences of extremely short event durations (and/or long grain durations). Where this can happen as a side-effect, thresholds can be built in. 

+

Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended - and if more complications are involved: testing without sound first, after saving your patch, might be a good idea.

+


+


+

NOTE: 

+


+

With the exception of Exs. 2d all examples use SoundIn, supposing to use input from your computer resp. soundcard. Depending on your setup you might have to change the standard input (bus = 0) passed to VarGui resp. the SoundIn ugen. Use headphones to avoid feedback!

+


+


+

NOTE: 

+


+

All live granulation variants of this file can of course be applied to any signal, thus also to any playback of a buffer. Vice versa all variants from Buffer Granulation can be applied to a buffer, which is occasionally (or continuously) filled with live input.

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

1.) Live granulation scheduled by server

+


+

This can be done with the GrainIn ugen or self-defined enveloping. An advantage of server-driven live granulation is, that accuracy issues and their workarounds, as described in Exs. 2a-2d, are avoided. As a restriction, sequenced processing of grains, e.g. as with PbindFx, is more difficult.

+


+


+

Example 1a:   Basic live granulation with GrainIn

+


+

(

+

~audioBus_ex_1a = Bus.audio(s, 1);

+


+

// pass envelopes with buffer, hanning is GrainIn's default anyway

+

h = Signal.hanningWindow(1000);

+

e = Buffer.loadCollection(s, h);

+


+

SynthDef(\soundIn, { |out, in, ampIn = 1|

+

Out.ar(out, SoundIn.ar(in) * ampIn)

+

}).add;

+


+

SynthDef(\live_gran_1a, { |out, in, envBuf, trigRate = 50, overlap = 0.5, panMax = 0.5,

+

panType = 0, amp = 1, minGrainDur = 0.001|

+

var inSig, sig, trig, grainDur, pan;

+


+

inSig = In.ar(in, 1);

+

// reduce feedback

+

inSig = DelayC.ar(LPF.ar(inSig.tanh, 2000), 0.1, 0.01);

+


+

trig = Impulse.ar(trigRate);

+

grainDur = max(trigRate.reciprocal * overlap, minGrainDur);

+


+

// select L/R or random sequencing

+

pan = Demand.ar(

+

trig,

+

0,

+

Dswitch1([

+

Dseq([1, -1], inf),

+

Dwhite(-1, 1)

+

], panType)

+

) * min(panMax, 0.999);

+


+

sig = GrainIn.ar(

+

2,

+

trig,

+

grainDur,

+

inSig,

+

pan,

+

envBuf

+

);

+

Out.ar(out, sig * EnvGate.new * amp);

+

}).add;

+

)

+


+


+

// to avoid feedback use with headphones 

+


+

(

+

// start granulation (first row) before to ensure right order

+

VarGui(

+

synthCtr: [

+

[

+

\envBuf, e.bufnum,

+

\in, ~audioBus_ex_1a.index,

+

\trigRate, [5, 500, \lin, 0, 50],

+

\overlap, [0.05, 3, \lin, 0, 0.5],

+

\panType, [0, 1, \lin, 1, 0],

+

\panMax, [0, 1, \lin, 0, 0.5],

+

\amp, [0, 1, \lin, 0, 0.1]

+

],[

+

\out, ~audioBus_ex_1a.index,

+

// you might have to pass a different 'in' bus for SoundIn

+

// depending on your setup

+

\in, 0,

+

\ampIn, [0, 1, \lin, 0, 1]

+

]

+

],

+

synth: [\live_gran_1a, \soundIn]

+

).gui

+

)

+


+


+

Even with overlapping grains, sequenced effect processing per grain is possible with GrainIn, but requires more effort, see Ex. 1e in the Buffer Granulation tutorial.

+


+


+

Example 1b:   Live granulation with server-driven enveloping

+


+

In this example only non-overlapping grains are regarded, for overlapping a multichannel approach as in Ex. 1e of the Buffer Granulation tutorial can be applied. In comparison to live granulation example 1a there is hardly an advantage in this basic variant. However intermediate processings can be built into this SynthDef, which aren't possible in the above example, where granulation is encapsulated in a UGen, manipulation of the envelope signal could be one.

+


+

(

+

~audioBus_ex_1b = Bus.audio(s, 1);

+


+

// pass envelopes with buffer

+

h = Signal.hanningWindow(1000);

+

e = Buffer.loadCollection(s, h);

+


+

SynthDef(\soundIn, { |out, in, ampIn = 1|

+

Out.ar(out, SoundIn.ar(in) * ampIn)

+

}).add;

+


+

// suppose overlap < 1

+


+

SynthDef(\live_gran_1b, { |out, in, envBuf, trigRate = 50, overlap = 0.5, panMax = 0.5,

+

panType = 0, amp = 1, minGrainDur = 0.001, interpolation = 4|

+

var inSig, env, numFrames = BufFrames.kr(envBuf), startTrig, grainDur,

+

latchedTrigRate, latchedStartTrig, latchedOverlap, pan;

+


+

inSig = In.ar(in, 1);

+

// reduce feedback

+

inSig = DelayC.ar(LPF.ar(inSig.tanh, 2000), 0.1, 0.01);

+


+

startTrig = Impulse.ar(trigRate);

+

// why this ? - shape of envelope shouldn't be changed while application

+

latchedTrigRate = Latch.ar(K2A.ar(trigRate), startTrig);

+

latchedStartTrig = Impulse.ar(latchedTrigRate);

+

latchedOverlap = Latch.ar(K2A.ar(overlap), startTrig);

+


+

latchedOverlap = max(latchedOverlap, latchedTrigRate * minGrainDur);

+

grainDur = (latchedOverlap / latchedTrigRate);

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

latchedStartTrig,

+

latchedOverlap.reciprocal * latchedTrigRate * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+


+

pan = Demand.ar(

+

latchedStartTrig,

+

0,

+

Dswitch1([

+

Dseq([1, -1], inf),

+

Dwhite(-1, 1)

+

], panType)

+

) * panMax * 0.999;

+


+

Out.ar(out, Pan2.ar(inSig * env * amp, pan) * EnvGate.new);

+

}).add

+

)

+


+


+

// to avoid feedback use with headphones 

+


+

(

+

// start granulation (first row) before to ensure right order

+

VarGui(

+

synthCtr: [

+

[

+

\envBuf, e.bufnum,

+

\in, ~audioBus_ex_1b.index,

+

\trigRate, [5, 500, \lin, 0, 50],

+

\overlap, [0.05, 0.99, \lin, 0, 0.5],

+

\panType, [0, 1, \lin, 1, 0],

+

\panMax, [0, 1, \lin, 0, 0.5],

+

\amp, [0, 1, \lin, 0, 0.1]

+

],[

+

\out, ~audioBus_ex_1b.index,

+

// you might have to pass a different 'in' bus for SoundIn

+

// depending on your setup

+

\in, 0,

+

\ampIn, [0, 1, \lin, 0, 1]

+

]

+

],

+

synth: [\live_gran_1b, \soundIn]

+

).gui

+

)

+


+


+


+

+

2.) Live granulation driven by language

+


+

The crucial point of this strategy is a kind of incompatibility of In.ar and OffsetOut. Normally we use OffsetOut for exact buffer granulation with patterns, as the start of the synth (the grain) is corrected by a shift (standard Out.ar is only able to start at control block boundaries). However, when In.ar and OffsetOut.ar are used in the same synth the read input signal is also shifted, which results in a correct grain distance but an fluctuating input delay. This can be overcome by a little trick: we can use OffsetOut to send a trigger to a bus, which indicates its correct delay. Then the trigger can be read in the same synth and trigger again a gated envelope for the input signal, the resulting grain can be output with normal Out.ar. So grain distances are correct and input is not fluctuating (see Ex. 2d for an accuracy comparison). Nevertheless language-driven sequencing is not sample-exact in realtime, no matter if In.ar is used or not, this is related to hardware control and cannot be overcome. This might be an issue with a strictly periodic input signal and very short grain distances. You can e.g. check out with granulation of a fixed-pitch triangular wave or similar, every few seconds or so there will happen an audible jump due to an irregular time interval, which is necessary for clock calibration; at that point there will, in general, also be a phase shift of the input signal (see last example of 2d). This might not be noticed with an input of spoken voice e.g.

+

Control block length is also a boundary for gated envelopes defined with EnvGen – here envelopes are established with an env buffer used by BufRd and Sweep ugens, a flexible method as Envelopes shape can be defined arbitrarily in language.

+


+


+

Example 2a:   Basic Pbind live granulation

+


+

At that point I haven't seen a solution to pass the trigger bus as argument, in the example it is hard-wired. As the SynthDef uses a SetResetFF ugen, which relies on two triggers within control block length, grainDelta shouldn't be shorter than that. If shorter grainDeltas are required this would be possible with alternating SynthDefs and buses. For the same reason this SynthDef should only be used once at the same time by a Pbind/EventStreamPlayer. Alternatively – as in Ex. 2b – a SynthDef factory can produce a number of structurally equal SynthDefs bound to a number of buses.

+


+


+

(

+

// input bus and trigger bus

+

// trigger bus must be hard-wired in SynthDef though

+


+

~audioBus_ex_2a = Bus.audio(s, 1);

+

~trigBus_ex_2a = Bus.audio(s, 1);

+


+

// pass envelopes with buffer

+

h = Signal.hanningWindow(1000);

+

e = Buffer.loadCollection(s, h);

+


+

SynthDef(\soundIn, { |out, in, ampIn = 1|

+

Out.ar(out, SoundIn.ar(in) * ampIn)

+

}).add;

+


+

SynthDef(\live_gran_2a, { |out, inBus, envBuf, grainDelta, pan = 0,

+

overlap = 1, amp = 1, minGrainDur = 0.001, interpolation = 4|

+


+

var inSig, offset, env, numFrames = BufFrames.ir(envBuf), gate,

+

defaultOffset = ControlRate.ir.reciprocal;

+

inSig = In.ar(inBus, 1);

+

+

// reduce feedback

+

inSig = LPF.ar(inSig.tanh, 2000);

+


+

// low overlap bound given by minimal grain duration

+

overlap = max(overlap, minGrainDur / grainDelta);

+


+

// impulse for offset check

+

OffsetOut.ar(~trigBus_ex_2a, Impulse.ar(0));

+


+

// additional gate to start with 0 in delayed case

+

// this is necessary as OffsetOut outputs impulse twice

+

gate = SetResetFF.ar(In.ar(~trigBus_ex_2a));

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

In.ar(~trigBus_ex_2a),

+

(overlap * grainDelta).reciprocal * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+

// to finish synth

+

Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2);

+


+

// shifted accurate output

+

Out.ar(out, Pan2.ar(env * gate * inSig * amp, pan));

+

}).add

+

)

+


+


+

// to avoid feedback use with headphones 

+


+

// start synth and event stream player

+


+

(

+

p = Pbind(

+

\instrument, \live_gran_2a,

+

\inBus, ~audioBus_ex_2a,

+

\envBuf, e,

+

\dur, Pfunc { ~trigRate.reciprocal },

+

\grainDelta, Pkey(\dur),

+

\overlap, Pfunc { ~overlap },

+

\amp, Pfunc { ~amp },

+

\pan, Pfunc { ~panMax } * PLseq([1, -1]),

+

\addAction, \addToTail

+

);

+


+

VarGui([

+

\trigRate, [20, 500, \lin, 0, 100],

+

\overlap, [0.1, 2, \lin, 0, 0.5],

+

\panMax, [0, 1, \lin, 0, 0.5],

+

\amp, [0, 1, \lin, 0, 0.1]

+

],[

+

\out, ~audioBus_ex_2a.index,

+

// you might have to pass a different 'in' bus for SoundIn

+

// depending on your setup

+

\in, 0,

+

\ampIn, [0, 1, \lin, 0, 1]

+

], p, \soundIn

+

).gui

+

)

+


+


+


+


+

Example 2b:   Parallel Pbind live granulation

+


+

As trigger buses have to be hard-wired, a SynthDef factory produces a number of structurally equal SynthDefs bound to a number of buses. In this variant the granulation is combined with a bandpass filter.

+


+

(

+

// input bus and trigger bus

+

// trigger bus must be hard-wired in SynthDef though

+


+

~audioBus_ex_2b = Bus.audio(s, 1);

+


+

// pass envelopes with buffer

+

h = Signal.hanningWindow(1000);

+

e = Buffer.loadCollection(s, h);

+


+

SynthDef(\soundIn, { |out, in, ampIn = 1|

+

Out.ar(out, SoundIn.ar(in) * ampIn)

+

}).add;

+


+

// "SynthDef factory", as each SynthDef neads hard-wired bus, make 3 of each

+


+

~trigBus_ex_2b = { Bus.audio(s, 1) } ! 3;

+


+

{ |i|

+

var name = \live_gran_2b ++ "_" ++ i.asString;

+

SynthDef(name, { |out, inBus, envBuf, grainDelta, pan = 0, rq = 0.1, center = 500,

+

overlap = 1, amp = 1, minGrainDur = 0.001, interpolation = 4|

+


+

var sig, inSig, offset, env, numFrames = BufFrames.ir(envBuf), gate,

+

defaultOffset = ControlRate.ir.reciprocal;

+

inSig = In.ar(inBus, 1);

+

+

// reduce feedback

+

inSig = LPF.ar(inSig.tanh, 2000);

+


+

// amplitude compensation for lower rq of bandpass filter

+

inSig = BPF.ar(inSig, center, rq, (rq ** -1) * (400 / center ** 0.5));

+


+

// low overlap bound given by minimal grain duration

+

overlap = max(overlap, minGrainDur / grainDelta);

+


+

// impulse for offset check

+

OffsetOut.ar(~trigBus_ex_2b[i], Impulse.ar(0));

+


+

// additional gate to start with 0 in delayed case

+

// this is necessary as OffsetOut outputs impulse twice

+

gate = SetResetFF.ar(In.ar(~trigBus_ex_2b[i]));

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

In.ar(~trigBus_ex_2b[i]),

+

(overlap * grainDelta).reciprocal * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+

// to finish synth

+

Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2);

+


+

sig = env * gate * inSig * amp;

+


+

// shifted accurate output

+

Out.ar(out, Pan2.ar(sig, pan));

+

}).add

+

} ! 3

+

)

+


+


+

// to avoid feedback use with headphones 

+


+

// start synth and event stream players

+


+

(

+

// pattern maker, we need the three different instruments

+

p = { |i| Pbind(

+

\instrument, \live_gran_2b ++ "_" ++ i.asString,

+

\inBus, ~audioBus_ex_2b,

+

\envBuf, e,

+

\dur, Pfunc { ~trigRate.reciprocal },

+

\grainDelta, Pkey(\dur),

+

\overlap, Pfunc { ~overlap },

+

\rq, Pfunc { ~rq },

+

\center, Pfunc { ~center },

+

\amp, Pfunc { ~amp },

+

\pan, Pfunc { ~panMax } * PLseq([1, -1]),

+

\addAction, \addToTail

+

) };

+


+

VarGui([

+

\trigRate, [20, 500, \lin, 0, 100],

+

\overlap, [0.1, 2, \lin, 0, 0.5],

+

\panMax, [0, 1, \lin, 0, 0.5],

+

\center, [100, 3000, \exp, 0, 800],

+

\rq, [0.1, 1, \lin, 0, 0.1],

+

\amp, [0, 1, \lin, 0, 0.1]

+

] ! 3,[

+

\out, ~audioBus_ex_2b.index,

+

// you might have to pass a different 'in' bus for SoundIn

+

// depending on your setup

+

\in, 0,

+

\ampIn, [0, 1, \lin, 0, 1]

+

], p ! 3, \soundIn

+

).gui

+

)

+


+


+


+

Example 2c:   Live granulation with PbindFx

+


+


+

// extended ressources needed

+


+

(

+

s.options.numPrivateAudioBusChannels = 1024;

+

s.options.memSize = 8192 * 16;

+

s.reboot;

+

)

+


+


+

(

+

// input bus and trigger bus

+

// trigger bus must be hard-wired in SynthDef though

+


+

~audioBus_ex_2c = Bus.audio(s, 1);

+

~trigBus_ex_2c = Bus.audio(s, 1);

+


+

// pass envelopes with buffer

+

h = Signal.hanningWindow(1000);

+

e = Buffer.loadCollection(s, h);

+


+

SynthDef(\soundIn, { |out, in, ampIn = 1|

+

Out.ar(out, SoundIn.ar(in) * ampIn)

+

}).add;

+


+


+

// two fx SynthDefs

+


+

SynthDef(\resample, { |out = 0, in, mix = 0.5, amp = 1, resampleRate = 44100|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = Latch.ar(inSig, Impulse.ar(resampleRate));

+

    Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp);

+

}).add;

+


+

SynthDef(\bpf, { |out = 0, in, freq = 440, rq = 0.1, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = BPF.ar(inSig, freq, rq, (rq ** -1) * (400 / freq ** 0.5));

+

    Out.ar(out, (mix * sig + ((1 - mix) * inSig)) * amp);

+

}).add;

+


+


+

SynthDef(\live_gran_2c, { |out, inBus, envBuf, grainDelta, pan = 0,

+

overlap = 1, amp = 1, minGrainDur = 0.001, interpolation = 4|

+


+

var inSig, offset, env, numFrames = BufFrames.ir(envBuf), gate,

+

defaultOffset = ControlRate.ir.reciprocal;

+

inSig = In.ar(inBus, 1);

+


+

// reduce feedback

+

inSig = LPF.ar(inSig.tanh, 2000);

+


+

// low overlap bound given by minimal grain duration

+

overlap = max(overlap, minGrainDur / grainDelta);

+


+

// impulse for offset check

+

OffsetOut.ar(~trigBus_ex_2c, Impulse.ar(0));

+


+

// additional gate to start with 0 in delayed case

+

// this is necessary as OffsetOut outputs impulse twice

+

gate = SetResetFF.ar(In.ar(~trigBus_ex_2c));

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

In.ar(~trigBus_ex_2c),

+

(overlap * grainDelta).reciprocal * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+

// to finish synth

+

Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2);

+


+

// shifted accurate output

+

Out.ar(out, Pan2.ar(env * gate * inSig * amp, pan));

+

}).add

+

)

+


+


+

(

+

// start without fx

+


+

~fxOrder = 0;

+


+

// playing the PbindFx in a new group ensures that soundIn synth is placed before when started later

+


+

g = Group.new;

+


+

p = PbindFx([

+

\instrument, \live_gran_2c,

+

\inBus, ~audioBus_ex_2c,

+

// allow hard-wired bus (bus connections check)

+

\otherBusArgs, [\inBus, ~trigBus_ex_2c.index.asFloat],

+

\envBuf, e,

+

\dur, 1 / PL(\trigRate),

+

\grainDelta, Pkey(\dur),

+

\overlap, PL(\overlap),

+

\amp, PL(\amp),

+

\pan, PL(\panMax) * PLseq([1, -1]),

+

\fxOrder, PL(\fxOrder, envir: 't'),

+

\cleanupDelay, 0.1,

+


+

\group, g

+

],[

+

\fx, \resample,

+

\mix, 1,

+

\amp, PL(\amp_resample),

+

\resampleRate, PL(\resampleRate_resample),

+

\cleanupDelay, 0.01

+

],[

+

\fx, \bpf,

+

\freq, PL(\freq_bpf),

+

\rq, PL(\rq_bpf),

+

\mix, 1,

+

\amp, PL(\amp_bpf),

+

\cleanupDelay, 0.01

+

]

+

);

+


+

VarGui([

+

\trigRate, [20, 500, \lin, 0, 100],

+

\overlap, [0.1, 2, \lin, 0, 0.5],

+

\panMax, [0, 1, \lin, 0, 0.5],

+

\amp, [0, 1, \lin, 0, 0.1],

+


+

\resampleRate_resample, [200, 3000, \exp, 0, 500],

+

\amp_resample, [0, 1, \lin, 0, 1],

+


+

\freq_bpf, [50, 3000, \exp, 0, 200],

+

\rq_bpf, [0.1, 1, \lin, 0, 0.3],

+

\amp_bpf, [0, 1, \lin, 0, 1]

+

],[

+

\out, ~audioBus_ex_2c.index,

+

// you might have to pass a different 'in' bus for SoundIn

+

// depending on your setup

+

\in, 0,

+

\ampIn, [0, 1, \lin, 0, 1]

+

], p, \soundIn

+

).gui(

+

    varColorGroups: (0..8).clumps([4, 2, 3]),

+

    tryColumnNum: 1,

+

    labelWidth: 140,

+

    sliderWidth: 350

+

)

+

)

+


+


+

// check fxs and their params, mix is fixed to 1

+


+

// resample

+


+

~fxOrder = 1

+


+


+

// band pass

+


+

~fxOrder = 2

+


+


+

// resample -> band pass

+


+

~fxOrder = [1, 2]

+


+


+

// band pass -> resample 

+


+

~fxOrder = [2, 1]

+


+


+

// fx alternations

+

// Pstutter with repeats equal 2 ensures L/R balance

+


+

~fxOrder = Pstutter(2, PLseq([1, 2]))

+


+

~fxOrder = Pstutter(2, PLseq([[1, 2], 1]))

+


+

~fxOrder = Pstutter(2, PLseq([[1, 2], 2]))

+


+


+

~fxOrder = Pstutter(2, PLseq([[2, 1], 1]))

+


+

~fxOrder = Pstutter(2, PLseq([[2, 1], 2]))

+


+


+

~fxOrder = Pstutter(2, PLseq([[1, 2], [2, 1]]))

+


+


+


+


+

Example 2d:   Accuracy comparison

+


+

This example compares the inaccuracies occuring with "normal" usage of Out.ar and the usage of In.ar + OffsetOut.ar with the strategy recommended in Ex. 2a. Run the three examples, the audio output is played and recorded into three files in the recordings directory (you get the path with thisProcess.platform.recordingsDir).

+


+


+

// test with source of added sines, inaccuracies with straight use of Out.ar

+


+

(

+

~audioBus_ex_2d1 = Bus.audio(s, 1);

+


+

// pass envelopes with buffer

+

// envelope with sharp attack to make effect more clear

+

h = Env([0, 1, 1, 0], [1, 10, 1].normalizeSum, curve: \sine).discretize(1000);

+

e = Buffer.loadCollection(s, h);

+


+

// sine as test signal

+

SynthDef(\sineIn, { |directOut, granOut, freq = 200, amp = 0.03, in|

+

freq = freq * (1..8);

+

Out.ar(directOut, SinOsc.ar(freq).sum * amp * EnvGate.new);

+

Out.ar(granOut, SinOsc.ar(freq).sum * amp);

+

}).add;

+


+

// envelopes in left channel, granulation in right

+

SynthDef(\live_gran_shaky_1, { |out, inBus, envBuf, grainDelta,

+

overlap = 1, amp = 1, interpolation = 4|

+


+

var inSig, offset, env, numFrames = BufFrames.ir(envBuf),

+

defaultOffset = ControlRate.ir.reciprocal;

+

inSig = In.ar(inBus, 1);

+

+

// reduce feedback with sound in source

+

inSig = LPF.ar(inSig.tanh, 2000);

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

1,

+

(overlap * grainDelta).reciprocal * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+

// to finish synth

+

Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2);

+


+

Out.ar(out + 1, inSig * env);

+

}).add;

+


+


+

p = Pfindur(1, Pbind(

+

\instrument, \live_gran_shaky_1,

+

\inBus, ~audioBus_ex_2d1,

+

\envBuf, e,

+

\dur, 0.005,

+

\grainDelta, Pkey(\dur),

+

\overlap, 0.5,

+

\amp, 0.1,

+

\addAction, \addToTail

+

));

+

)

+


+


+

(

+

// record live input and granulation (which comes with delay due to normal pbind latency)

+

// see the file in an editor then:

+

// distances are irregular due to Out ugen's accuracy limit control block boundary,

+

// though source signal is not delayed

+


+

{

+

~date = Date.getDate.stamp;

+

~fileName = thisProcess.platform.recordingsDir +/+

+

("live_gran_shaky_1" ++ "_" ++ ~date ++ ".aiff");

+

s.record(~fileName);

+

s.sync;

+


+

x = Synth(\sineIn, args: [directOut: 0, granOut: ~audioBus_ex_2d1]);

+

p.play;

+


+

1.5.wait;

+

x.release;

+

s.stopRecording;

+

}.fork

+

)

+


+


+


+

/////////////////////////

+


+

// test with source of added sines, inaccuracies with use of In.ar + OffsetOut.ar 

+


+

(

+

~audioBus_ex_2d2 = Bus.audio(s, 1);

+


+

// pass envelopes with buffer

+

// envelope with sharp attack to make effect more clear

+

h = Env([0, 1, 1, 0], [1, 10, 1].normalizeSum, curve: \sine).discretize(1000);

+

e = Buffer.loadCollection(s, h);

+


+

// sine as test signal

+

SynthDef(\sineIn, { |directOut, granOut, freq = 200, amp = 0.03, in|

+

freq = freq * (1..8);

+

Out.ar(directOut, SinOsc.ar(freq).sum * amp * EnvGate.new);

+

Out.ar(granOut, SinOsc.ar(freq).sum * amp);

+

}).add;

+


+

// envelopes in left channel, granulation in right

+

SynthDef(\live_gran_shaky_2, { |out, inBus, envBuf, grainDelta,

+

overlap = 1, amp = 1, interpolation = 4|

+


+

var inSig, offset, env, numFrames = BufFrames.ir(envBuf),

+

defaultOffset = ControlRate.ir.reciprocal;

+

inSig = In.ar(inBus, 1);

+


+

// reduce feedback with sound in source

+

inSig = LPF.ar(inSig.tanh, 2000);

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

1,

+

(overlap * grainDelta).reciprocal * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+

// to finish synth

+

Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2);

+


+

OffsetOut.ar(out + 1, inSig * env);

+

}).add;

+


+


+

p = Pfindur(1, Pbind(

+

\instrument, \live_gran_shaky_2,

+

\inBus, ~audioBus_ex_2d2,

+

\envBuf, e,

+

\dur, 0.005,

+

\grainDelta, Pkey(\dur),

+

\overlap, 0.5,

+

\amp, 0.1,

+

\addAction, \addToTail

+

));

+

)

+


+


+

// record live input and granulation (which comes with delay due to normal pbind latency)

+

// see the file in an editor then:

+

// distances are regular due to OffsetOut, but source signal is delayed

+

// between 0 and control block length

+


+

(

+

{

+

~date = Date.getDate.stamp;

+

~fileName = thisProcess.platform.recordingsDir +/+

+

("live_gran_shaky_2" ++ "_" ++ ~date ++ ".aiff");

+

s.record(~fileName);

+

s.sync;

+


+

x = Synth(\sineIn, args: [directOut: 0, granOut: ~audioBus_ex_2d2]);

+

p.play;

+


+

1.5.wait;

+

x.release;

+

s.stopRecording;

+

}.fork

+

)

+


+


+


+

/////////////////////////

+


+

// test with source of added sines, granulation done as in Ex. 2a  

+


+

(

+

// input bus and trigger bus

+

// trigger bus must be hard-wired in SynthDef though

+


+

~audioBus_ex_2d3 = Bus.audio(s, 1);

+

~trigBus_ex_2d3 = Bus.audio(s, 1);

+


+


+

// pass envelopes with buffer

+

// envelope with sharp attack to make effect more clear

+

h = Env([0, 1, 1, 0], [1, 10, 1].normalizeSum, curve: \sine).discretize(1000);

+

e = Buffer.loadCollection(s, h);

+


+

// sine as test signal

+

SynthDef(\sineIn, { |directOut, granOut, freq = 200, amp = 0.03, in|

+

freq = freq * (1..8);

+

Out.ar(directOut, SinOsc.ar(freq).sum * amp * EnvGate.new);

+

Out.ar(granOut, SinOsc.ar(freq).sum * amp);

+

}).add;

+


+

// envelopes in left channel, granulation in right

+

SynthDef(\live_gran_ok, { |out, inBus, envBuf, grainDelta, gate,

+

overlap = 1, amp = 1, interpolation = 4|

+


+

var inSig, offset, env, numFrames = BufFrames.ir(envBuf),

+

defaultOffset = ControlRate.ir.reciprocal;

+

inSig = In.ar(inBus, 1);

+


+

// reduce feedback with sound in source

+

inSig = LPF.ar(inSig.tanh, 2000);

+


+

// impulse for offset check

+

OffsetOut.ar(~trigBus_ex_2d3, Impulse.ar(0));

+


+

// necessary additional gate to start with 0 in delayed case

+

gate = SetResetFF.ar(In.ar(~trigBus_ex_2d3));

+


+

env = BufRd.ar(

+

1,

+

envBuf,

+

Sweep.ar(

+

In.ar(~trigBus_ex_2d3),

+

(overlap * grainDelta).reciprocal * numFrames,

+

).clip(0, numFrames - 1),

+

interpolation: interpolation

+

);

+

// to finish synth

+

Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2);

+


+

// shifted accurate output

+

Out.ar(out + 1, inSig * env * gate);

+

}).add;

+


+


+

p = Pfindur(1, Pbind(

+

\instrument, \live_gran_ok,

+

\inBus, ~audioBus_ex_2d3,

+

\envBuf, e,

+

\dur, 0.005,

+

\grainDelta, Pkey(\dur),

+

\overlap, 0.5,

+

\amp, 0.1,

+

\addAction, \addToTail

+

));

+

)

+


+


+

(

+

// record live input and granulation (which comes with delay due to normal pbind latency)

+

// see the file in an editor then:

+

// distances are regular due to OffsetOut, and source signal is not delayed

+


+

// However also in this case, because of hardware output calibration, it happens that phase shifts

+

// occur in granulation.

+

// This is currently unavoidable in SC's realtime mode, but probably irrelevant in most cases of 

+

// live granulation, where there is no strictly periodic input signal

+


+

{

+

~date = Date.getDate.stamp;

+

~fileName = thisProcess.platform.recordingsDir +/+

+

("\live_gran_ok" ++ "_" ++ ~date ++ ".aiff");

+

s.record(~fileName);

+

s.sync;

+


+

x = Synth(\sineIn, args: [directOut: 0, granOut: ~audioBus_ex_2d3]);

+

p.play;

+


+

1.5.wait;

+

x.release;

+

s.stopRecording;

+

}.fork

+

)

+


+


+ + diff --git a/Help/MemoRoutine.html b/Help/MemoRoutine.html new file mode 100755 index 0000000..bdc5700 --- /dev/null +++ b/Help/MemoRoutine.html @@ -0,0 +1,266 @@ + + + + + + + + + + + +

MemoRoutine Routine-like object which stores last values

+


+

Part of: miSCellaneous

+


+

Inherits from: Stream

+


+

A MemoRoutine behaves like a Routine, though it is not defined as a subclass of it. It stores last values, the maximum buffer size can be defined. MemoRoutine is internally used by PSx and related Pattern classes, which therefore also remember their last value(s). 

+


+

See also: Routine, PSx stream patterns, PS, PSdup, PSrecur

+


+


+

Creation / Class Methods

+


+

*new (func, stackSize, bufSize, copyItems, copySets)

+

+

Creates a MemoRoutine instance with the given Function.

+

+

func - Function to instantiate the Routine with.

+

stackSize - Call stack depth, defaults to 512.

+

bufSize - Number of last values to store, defaults to 1.

+

copyItems - Determines if and how to copy items, which are returned by method next 

+

(run, value, resume) and which are either non-Sets or member of Sets, into the buffer. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). 

+

Other values are interpreted as 0. Defaults to 0.

+

0: storage of original item 

+

1: storage of copied item

+

2: storage of deepCopied item

+

copySets - Determines if to copy Sets (and hence Events), 

+

which are returned by method next (run, value, resume), into the buffer. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). 

+

Other values are interpreted as 0. Defaults to 1.

+

0: storage of original Set 

+

1: storage of copied Set

+

+

NOTE: The distinction of copying items and sets makes sense in the case of event streams.

+

Per default Events are copied (copySets == 1), not their values (copyItems == 0). 

+

By playing Events those are used to store additional data (synth ids, msgFuncs …) 

+

which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use 

+

MemoRoutine - copied Events will not contain this additional data. 

+

If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured 

+

then copying makes no sense, this is the normal case, so copyItems defaults to 0.

+

When going to alter the ouput, you might want to set copyItems to 1 for a MemoRoutine returning 

+

simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set

+

copySets to 1 and copyItems to 2 (an option copySets == 2 doesn't exist as

+

it would be contradictory in combination with copyItems < 2).

+

+

+


+

Instance Methods

+


+

next (inval)

+

+

inval - Same conventions with method yield as with aRoutine.next.

+


+

value (inval)

+

+

Same as next.

+


+

resume (inval)

+

+

Same as next.

+


+

run (inval)

+

+

Same as next.

+

+

lastValue

+

+

Last value.

+


+

lastValues

+

+

Instance variable getter method for array of stored last values.

+

+

at (i)

+

+

Returns ith item of array of last values (keep in mind reversed order: last value first)

+

+

bufSize

+

+

Size of array of last values.

+


+

reset

+

+

Resets the MemoRoutine by resetting its Routine.

+


+

stop

+

+

Stops the MemoRoutine by stopping its Routine.

+


+

count, count_(value)

+

+

Instance variable getter and setter methods.

+

Counts each call of next / value / resume / run. 

+


+

copyItems, copyItems_(value)

+

+

Instance variable getter and setter methods. 

+

If used directly the Integer copy code must be passed (see above).

+

+

copySets, copySets_(value)

+

+

Instance variable getter and setter methods.

+

If used directly the Integer copy code must be passed (see above).

+


+

routine, routine_(value)

+

+

Instance variable getter and setter methods. 

+


+

+

Examples

+


+

(

+

// a MemoRoutine

+


+

m = MemoRoutine(

+

{ |inval| 1000.do { |i| inval = i.yield } },

+

bufSize: 50

+

);

+

)

+


+

m.nextN(5);

+


+


+

// get last value

+


+

m.lastValue;

+


+

m[0];

+


+


+

// get last values, order is from last to earlier

+


+

m.lastValues;

+


+


+

// get value before last value

+


+

m[1];

+


+


+


+

// get more values

+


+

m.nextN(100);

+


+


+


+

// first values are lost now

+


+

m.lastValues;

+


+


+

// as loop in m is restricted you might call .all

+

// as stop is indicated by the return of nil, 

+

// the array lastValues contains nil as first item

+


+

m.all;

+


+

m.lastValues;

+


+


+


+

// Per default a MemoRoutine is just storing the last values,

+

// with structured data types this can cause surprises 

+


+

(

+

// a MemoRoutine

+


+

m = MemoRoutine(

+

{ |inval| var a = [[2,1], [4,3]]; 1000.do { inval = a.choose.yield } },

+

bufSize: 50

+

);

+

)

+


+

// generate some values

+


+

m.nextN(10);

+


+

// apply a method on last values

+


+

(

+

x = m.lastValue;

+

x.sort;

+

)

+


+

// as sort is destructive one of MemoRoutine's arrays is altered now !

+


+

m.nextN(10);

+


+


+


+

// to avoid such you can simply do .copy.sort which doesn't alter lastValues,

+

// but you can also store copied values in the buffer by passing a flag with

+

// instantiation of the MemoRoutine

+


+

(

+

// a MemoRoutine which stores copied arrays

+


+

m = MemoRoutine(

+

{ |inval| var a = [[2,1], [4,3]]; 1000.do { inval = a.choose.yield } },

+

bufSize: 100,

+

copyItems: 1 // 1, true or \true for copy, 2 or \deep for deepCopy

+

);

+

)

+


+

m.nextN(10);

+


+

(

+

x = m.lastValue;

+

x.sort;

+

)

+


+

// order not altered with next items

+


+

m.nextN(10);

+


+

// however the concerned array stored as item in lastValues remains altered

+


+

m[10];

+


+


+


+


+


+ + diff --git a/Help/Other event and pattern shortcuts.html b/Help/Other event and pattern shortcuts.html new file mode 100644 index 0000000..2266217 --- /dev/null +++ b/Help/Other event and pattern shortcuts.html @@ -0,0 +1,297 @@ + + + + + + + + + + + +

Other event and pattern shortcuts various shortcut writings for events and patterns

+


+

Part of: miSCellaneous

+


+

See also: EventShortcuts, PLx and live coding with Strings

+


+

Apart from the class EventShortcuts itself, which handles bookkeeping of shortcut dictionaries, miSCellaneous lib includes some additional shortcut methods for generation and playing of events and different types of event patterns from SequenceableCollections. These methods support functional conventions for reference.

+


+


+

1.) Event shortcuts

+


+

1a: Event methods 

+


+

anEvent.on

+

+

Plays an Event. If dur isn't specified it is set to inf.

+

+

anEvent.off(releaseTime)

+

+

Releases the Event's node. 

+

+

releaseTime - SimpleNumber for release time. Defaults to nil (default release time of event mechanism)

+


+


+


+

Examples

+

+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// start default synth

+


+

x = ().on

+


+


+

// release with 3 seconds releaseTime 

+


+

x.off(3)

+


+


+

// with EventShortcuts turned on this gives a quick way to run synths,

+

// here default synth with replacements 'n' -> 'note' and 'd' -> 'dur'.

+


+


+

EventShortcuts.makeCurrent(\default).on

+


+

(n: [0, 4, 7, 12], d: 3).on

+


+


+

// define SynthDef 

+


+

SynthDef(\x, { |out = 0, freq = 440, amp = 0.05| Out.ar(0, SinOsc.ar(freq, 0, amp) * EnvGate.new) }).add

+


+


+

// run synth, audible beats with equal temperature, pitches given as notes ('n')

+


+

(i: \x, n: [0, 4, 7], d: 3).on

+


+


+

// not with just intonation, pitches given as frequencies ('f')

+


+

(i: \x, f: (4..6) * 100, d: 3).on

+


+


+


+


+

1b: Event-related methods defined for SequenceableCollections

+


+

aSequenceableCollection.ev

+

+

Derives an Event from an array of key/value-pairs. Values might be functions that refer to 

+

prior keys of the array.

+

+

aSequenceableCollection.on

+

+

Derives an Event from an array with method ev and plays it using on.

+

+


+


+


+

Example 

+


+


+

// define an array as event template

+

// references to prior keys can be written as environmental variables in Functions

+

// here: higher midinotes get shorter durations

+


+

(

+

a = [

+

m: { rrand(60, 100) }, // midinote

+

d: { ~m.linlin(60, 90, 3, 0.1) } // dur

+

]

+

)

+


+

// suppose EventShortCuts are turned on

+

// make an Event and see its data, then play, try several times

+


+


+

x = a.ev

+


+

x.on

+


+


+


+

// same can be done in one, try several times

+


+

a.on

+


+


+


+

2: Event-pattern-related methods defined for SequenceableCollections

+


+

aSequenceableCollection.pa

+

+

Expects basically an array of key/value-pairs ready for an event pattern. 

+

Exception: values might be functions that refer to prior keys of the array, thus delivering

+

an shortcut functionality of the common Pfunc { |e|  ... } construct (and similar to Pkey).

+

+

aSequenceableCollection.p

+

+

Derives a Pbind from an array involving pa.

+

+

aSequenceableCollection.pm(sym)

+

+

Derives a Pmono with instrument sym (a Symbol) from an array involving pa.

+

+

aSequenceableCollection.pma(sym)

+

+

Derives a PmonoArtic with instrument sym (a Symbol) from an array involving pa.

+


+

aSequenceableCollection.pbf(sym)

+

+

Derives a Pbindef with reference sym (a Symbol) from an array involving pa.

+


+


+


+

aSequenceableCollection.pp(clock, protoEvent, quant)

+

+

Derives and plays a Pbind from an array involving pa. 

+

Arguments clock, protoEvent and quant are used by Pattern's method play.

+

+

aSequenceableCollection.ppm(sym, clock, protoEvent, quant)

+

+

Derives and plays a Pmono with instrument sym (a Symbol) from an array involving pa.

+

Arguments clock, protoEvent and quant are used by Pattern's method play.

+

+

aSequenceableCollection.ppma(sym, clock, protoEvent, quant)

+

+

Derives and plays a PmonoArtic with instrument sym (a Symbol) from an array involving pa.

+

Arguments clock, protoEvent and quant are used by Pattern's method play.

+


+

aSequenceableCollection.ppbf(sym, clock, protoEvent, quant)

+

+

Derives and plays a Pbindef with reference sym (a Symbol) from an array involving pa.

+

Arguments clock, protoEvent and quant are used by Pattern's method play.

+


+


+


+

Examples

+


+

// use reference convention with Functions

+

// make an array of patternpairs to be used in different event pattern types

+


+

(

+

a = [

+

m: Pwhite(60, 80, 30), // midinote

+

d: { (~m > 70).if { 2 }{ 1 }/8 } // dur

+

].pa

+

)

+


+

Pbind(*a).play

+


+

Pmono(\default, *a).play

+


+


+


+

// define Pbind and play on different channels

+


+

(

+

p = [

+

m: Pwhite(60, 80, 100),

+

d: { (~m > 70).if { 2 }{ 1 }/8 }

+

].p

+

)

+


+

Pbindf(p, \p, -1).play(quant: 1/4) // \p for pan

+


+

Pbindf(p, \p, 1).play(quant: 1/4)

+


+


+


+

// same with Pmono ...

+


+

(

+

[

+

m: Pwhite(60, 80, 30),

+

d: { (~m > 70).if { 2 }{ 1 }/8 }

+

].pm(\default)

+

)

+


+

Pbindf(p, \p, -1).play(quant: 1/4)

+


+

Pbindf(p, \p, 1).play(quant: 1/4)

+


+


+


+

// ... and PmonoArtic

+


+

(

+

p = [

+

m: Pwhite(60, 80, 100),

+

d: { (~m > 70).if { 2 }{ 1 }/8 },

+

l: Pwhite(0.1, 1.5) // legato

+

].pma(\default)

+

)

+


+

Pbindf(p, \p, -1).play(quant: 1/4)

+


+

Pbindf(p, \p, 1).play(quant: 1/4)

+


+


+


+

// analogous definition with Pbindef

+

// example different as Pbindef is pattern and player in one

+


+

(

+

p = [

+

m: Pwhite(60, 80, 100),

+

d: { (~m > 70).if { 2 }{ 1 }/8 }

+

].pbf(\x)

+

)

+


+

Pbindef(\x, \p, -1).play

+


+

Pbindef(\x, \p, 1)

+


+

Pbindef(\x).clear

+


+


+


+

// immediately play Pbind

+

// also play Pmono, PmonoArtic and Pbindef directly with methods ppm, ppma and ppbdf 

+


+

(

+

[

+

m: Pwhite(60, 80, 30),

+

d: { (~m > 70).if { 2 }{ 1 }/8 }

+

].pp

+

)

+


+


+


+


+


+


+


+ + diff --git a/Help/PHS.html b/Help/PHS.html new file mode 100755 index 0000000..b7756ad --- /dev/null +++ b/Help/PHS.html @@ -0,0 +1,222 @@ + + + + + + + + + + + +

PHS (PHelpSynth) defines Pbind(s) for using synth values of a HS

+


+

Part of: miSCellaneous

+


+

Inherits from: PHSuse (PHelpSynthUse)

+


+

Defines Pbind(s) which, when played, can use values of a synth derived from HS's synth definition.

+


+

See also: Working with HS and HSpar, HS with VarGui, HS, PHSuse, PHSplayer, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (helpSynth, helpSynthArgs, dur1, pbindData1, ... , durN, pbindDataN)

+

+

Creates a new PHS object.

+

+

helpSynth - A HS object.

+

helpSynthArgs - Collection of key / value pairs for the HS synth.

+

dur i - Duration value or pattern / stream of durations for corresponding Pbind(s).

+

pbindData i - A collection of Pbind pairs or a collection of Pbind pair collections,

+

defining possibly several Pbinds with the same event timing. 

+


+


+

Status control

+


+

play(clock, quant)

+

+

A PHSplayer object is instantiated and started using the TempoClock clock. 

+

Quant or SimpleNumber quant lets the player step into the quantization as soon as possible, 

+

with respect to the necessary latency. The PHSplayer can be stopped and resumed with several options.

+


+


+

VarGui support

+


+

These two methods should be used when combining HS / PHS with VarGui, see HS with VarGui for examples.

+

+

+

newPaused(args, latency)

+

+

Return a new paused Synth derived from HS's ugenFunc definition, which may be passed to a VarGui object. 

+

VarGui will automatically detect that the Synth origins from a HS definition and gui functionality wil be adapted.

+

+

args - Collection of key / value pairs for the HS synth.

+

latency - SimpleNumber (seconds). 

+


+

+

asTask(clock, quant, hsStop, hsPlay, newEnvir, removeCtrWithCmdPeriod)

+

+

Returns a wrapper Task, which may be passed to a VarGui object. 

+

Playing and stopping the wrapper Task invokes playing and 

+

stopping behaviour of the underlying PHSplayer, per default also taking control over 

+

playing and stopping the help synth.

+

+

clock - TempoClock.

+

quant - Quant or SimpleNumber.

+

hsStop - Boolean. Determines if help synth will stop together with PHSplayer. Defaults to false.

+

hsPlay - Boolean. Determines if help synth will resume together with PHSplayer. Defaults to true.

+

newEnvir - Boolean. Determines if Task will be played in a newly generated environment. Defaults to true.

+

This option especially becomes important when PHS's pbindData contains functional code with 

+

environmental variables.

+

removeCtrWithCmdPeriod - Boolean. Defaults to true. 

+

Determines if notification of PHSplayer will be stopped with CmdPeriod.

+

+

+

Examples

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// define a HS with args

+


+

h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) });

+


+


+

// two Pbinds with different event timing reading from one help synth 

+

+

(

+

p = PHS(h, nil, // default help synth args

+

Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val), \amp, 0.08  ],

+

0.1, [ \midinote, Pkey(\val) + 9.5 + Pxrand([0, 2, 5],inf), \amp, 0.06 ]

+

).play;

+

)

+


+

// stop player and free HS, ready to be played again with the same or another PHS

+

+

p.free;

+


+


+

// now with synth args

+

+

(

+

p = PHS(h, [\freq, 2, \dev, 20], // more oscillation

+

Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val) - [0, 5, 10], \amp, 0.06 ],

+

0.1, [ \midinote, Pkey(\val) + 9.5 + Pxrand([0, 4, 7],inf), \amp, 0.06 ]

+

).play;

+

)

+


+


+

// stop player and free HS

+


+

p.free;

+


+


+


+

// let PHS define two Pbinds with same event timing, one mostly pausing

+


+

(

+

p = PHS(h, [], 0.16, 

+

[ [\midinote, Pkey(\val), \amp, 0.1], 

+

  [\midinote, Pkey(\val) + [-7, 4, 7],

+

\amp, Pwrand([0.04, 0.08], [0.8, 0.2], inf),

+

\type, Pkey(\val).collect { |x| x.asInteger.even.if { \note }{ \rest } } ] ]

+

).play;

+

)

+


+


+

// stop player and free HS

+


+

p.free;

+


+


+

// order of execution: three Pbinds defined, scheduling slightly time-shifted internally,

+

// so references can be established

+


+

// printout of variables which may be used within a PHS definition

+

// timeGrains is just a time ID, depending on granularity, not used for scheduling

+

// demandIndex indicates the index of the stream of durations

+

// posted demandIndex = 1, as two pbinds are using duration stream #0 

+


+


+

(

+

p = PHS(h, [], 

+

0.16, 

+

[ [\midinote, Pkey(\val) + Pseq([0,2], inf), \amp, 0.06], 

+

  [\midinote, Pkey(\val) + [-7, 4, 7],

+

\amp, Pwrand([0.06,0.1], [0.8,0.2], inf),

+

// "random" appearance of middle voice chords depending on synth values 

+

\type, Pkey(\val).collect { |x| ~middle = x.asInteger.even.if { \note }{ \rest } } ] ],

+

Pseq([0.32, 0.16], inf), 

+

[ [\midinote, Pkey(\val) + [15, 20, 25],

+

  \legato, 0.2,

+

  \amp, 0.025,

+

  // upper voice is playing in case of middle voice rest 

+

  \type, Pkey(\val).collect { |x| (~middle == \rest).if { \note }{ \rest } },

+

  \post, Pfunc { |e| e.use {

+

"demandIndex: ".post; ~demandIndex.postln;

+

"timeGrains: ".post; ~timeGrains.postln;

+

"dur: ".post; ~dur.postln;

+

"val: ".post; ~val.postln;

+

"================================".postln;

+

}

+

}

+

]]

+

).play;

+

)

+


+


+

// stop player and free HS

+


+

p.free;

+


+


+


+ + diff --git a/Help/PHSpar.html b/Help/PHSpar.html new file mode 100755 index 0000000..709a9ae --- /dev/null +++ b/Help/PHSpar.html @@ -0,0 +1,415 @@ + + + + + + + + + + + +

PHSpar (PHelpSynthPar) defines Pbind(s) for using synth values of a HSpar

+


+

Part of: miSCellaneous

+


+

Inherits from: PHSparUse (PHelpSynthParUse)

+


+

Defines Pbind(s) which, when played, can use values of synths derived from HSpar's synth definitions.

+


+

See also: Working with HS and HSpar, HS with VarGui, HSpar, PHSparUse, PHSparPlayer, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (helpSynthPar, switchDur, switchIndex, helpSynthArgs, pbindArgs, hsIndices, switchOn, switchOff, set, hsStartIndices)

+

+

Creates a new PHSpar object.

+

+

helpSynthPar - A HSpar object.

+

switchDur - Duration value or pattern / stream of durations determining the times of HSpar synth switches. 

+

switchIndex - Index or pattern / stream of indices determining HSpar's synth definition to switch to. 

+

Defaults to 0.

+

helpSynthArgs - Collection of Pbind pair collections (size = number of helpSynthPar's help synths), 

+

defining synth args to be set at switch times.

+

pbindArgs - Collection of the form [ dur1, pbindData1, ... , durN, pbindDataN ] , with

+

dur i - Duration value or pattern / stream of durations for corresponding Pbind(s).

+

pbindData i - A collection of Pbind pairs or a collection of Pbind pair collections, 

+

defining possibly several Pbinds with same event timing. 

+

hsIndices - Per default values are taken from the currently switched help synth. 

+

Explicitely given hsIndices allow reference to values of other help synths from the 

+

corresponding Pbind(s). See the examples below.

+

Expects a collection of valid hsIndex values resp. patterns / streams of valid hsIndex values.

+

A valid hsIndex value is a valid help synth index or a collection of valid help synth indices.

+

The collection's size must equal N, the number of pbindArgs's event timings.

+

switchOn - Boolean or pattern / stream of booleans, determining if switched help synths should be resumed. 

+

Defaults to false.

+

switchOff - Boolean or pattern / stream of booleans, determining if help synths, which are left at a switch, should be paused. 

+

Defaults to false.

+

set - Boolean or pattern / stream of booleans, determining if next synth input values, defined in helpSynthArgs, should be 

+

taken for setting the synth. The first help synth args are always set. Defaults to true.

+

hsStartIndices - A valid help synth index, a collection of valid help synth indices or one of the symbols: \all, \none. 

+

Determines which help synths should be started at the beginning in addition to the one of the first switch index. 

+

Help synths of other than first switch index are played with default args. 

+


+


+

VarGui support

+


+

These two methods should be used when combining HSpar / PHSpar with VarGui, see HS with VarGui for examples.

+

+

+

newPaused(args, latency)

+

+

Return a collection of new paused Synth(s) derived from HSpar's ugenFunc definition(s), which may be passed to a VarGui object. 

+

VarGui will automatically detect the origin from a HSpar definition and gui functionality wil be adapted.

+

+

args - Collection of collection(s) of key / value pairs for the HSpar synth(s).

+

latency - SimpleNumber (seconds). 

+


+


+

asTask(clock, quant, hsStop, hsPlay, switchStop, newEnvir, removeCtrWithCmdPeriod)

+

+

Returns a wrapper Task, which may be passed to a VarGui object. 

+

Playing and stopping the wrapper Task invokes playing and 

+

stopping behaviour of the underlying PHSparPlayer, per default also taking control over 

+

playing and stopping the help synth(s). See HS with VarGui for examples.

+

+

clock - TempoClock.

+

quant - Quant or SimpleNumber.

+

hsStop - Boolean, Integer or SequenceableCollection of Integers determining help synth indices. 

+

Determines if help synth(s) will stop together with PHSparPlayer. Defaults to false.

+

hsPlay - Boolean, Integer or SequenceableCollection of Integers determining help synth indices.

+

Determines if help synth(s) will resume together with PHSparPlayer. Defaults to true.

+

switchStop - Boolean. Determines if switching will stop together with PHSparPlayer. Defaults to true.

+

newEnvir - Boolean. Determines if Task will be played in a newly generated environment. Defaults to true.

+

This option especially becomes important when PHSpar's pbindData contains functional code with 

+

environmental variables.

+

removeCtrWithCmdPeriod - Boolean. Defaults to true. 

+

Determines if notification of PHSparPlayer will be stopped with CmdPeriod.

+


+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// define a HSpar with two help synth definitions 

+

+

(

+

h = HSpar(s, [ { |freq = 1, dev = 5, center = 65|

+

LFDNoise3.kr(freq, dev, center) },

+

{ |freq = 1, dev = 5, center = 75, addFreq = 0.1, addDev = 5|

+

LFTri.kr(freq, 0, dev, center) + SinOsc.kr(addFreq, 0, addDev) } 

+

]);

+

)

+


+

// define a PHSpar to switch between these two

+

// reference to currently switched help synth via ~val

+

// note that pbindArgs, different from PHS, have to be given as collection

+

+

(

+

p = PHSpar(h, 

+

3, // switch duration

+

Pseq([0,1],inf), // switch indices

+

// center of help synth #0 is reset at every switch, default values for help synth #1 :

+

[ [\center, Pseq([65, 90], inf)], nil], 

+

[0.1, [\midinote, Pkey(\val) /* ~val refers to current switch */ + Pseq([0,1],inf), \legato, 0.2 ] ]

+

).play;  

+

)

+

+

// stop and free HSpar

+

+

p.free;

+


+


+


+

// no need to define a switch pattern (default switch index = 0, default switch duration = inf)

+

// hsIndices value \all causes that all help synth values at corresponding Pbind times are accesible via ~vals

+

+

(

+

p = PHSpar(h, 

+

pbindArgs: [0.1, [\midinote, Pkey(\vals) /* collection, thus played as interval */ + Pseq([0,1],inf), 

+

\legato, 0.2 ] ],

+

hsIndices: [ \all ] 

+

).play;  

+

)

+

+

p.free;

+


+


+


+

// this is a bit wasteful as always both help synth values are demanded via the OSCresponder mechanism:

+

// see printed (serverToClient) OSC traffic

+

+

(

+

h.postOSC = true;

+


+

p = PHSpar(h, 

+

pbindArgs: [0.1, [\midinote, Pkey(\vals).collect(_.at(1)) /* take only the second */ + Pseq([0,1],inf), \legato, 0.2 ] ],

+

hsIndices: [ \all ] 

+

).play;  

+

)

+

+

p.free;

+


+


+


+

// the index may be determined by hsIndices 

+

// only the needed help synth value is demanded and can be referenced via ~thisVal:

+

// compare printed OSC traffic 

+


+

(

+

p = PHSpar(h, 

+

pbindArgs: [0.1, [\midinote, Pkey(\thisVal) /* take value determined by hsIndices */ + Pseq([0,1],inf), \legato, 0.2 ] ],

+

hsIndices: [ 1 ] 

+

).play;  

+

)

+


+

(

+

p.free;

+

h.postOSC = false;

+

)

+


+


+

// hsIndices may contain patterns

+

// only the needed help synth value is demanded and can be referenced via ~thisVal (or ~theseVals) :

+


+

(

+

p = PHSpar(h, 

+

pbindArgs: [0.1, [\midinote, Pkey(\thisVal) + Pseq([0,1],inf), \legato, 0.2 ] ],

+

hsIndices: [ Prand([0,1], inf) ] 

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// hsIndices also accepts collections of indices or patterns thereof, referenced by ~theseVals (which is always a collection)

+


+

(

+

p = PHSpar(h, 

+

pbindArgs: [0.1, [\midinote, Pkey(\theseVals) + Pseq([0,1],inf), \legato, 0.2 ] ],

+

hsIndices: [ Pstutter(Pwhite(5,10), Pxrand([0, 1, [0,1]], inf)) ] 

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// two Pbinds with different event timing

+

// hsIndices specified for each

+


+

(

+

p = PHSpar(h, // "+" wraps collections, so if ~theseVals is an interval then ~midinote consists of the two added sevenths [-5, 5], [0, 10], 

+

// otherwise ~midinote is a chord of fourths

+

pbindArgs: [0.2, [\midinote, Pkey(\theseVals) + [-5, 0, 5,10] , \legato, 0.2, \amp, 0.05 ],

+

0.1, [\midinote, Pkey(\thisVal) + Pseq([0,1],inf), \legato, 0.2, \amp, 0.08 ]],

+

hsIndices: [ Pstutter(Pwhite(5,10), Pxrand([0, 1, [0,1]], inf)), 0]

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// the switched indices can be referenced via the hsIndices arg by symbol \switch

+

// \all is synonym to [0,1] in the last example

+


+

(

+

p = PHSpar(h,

+

Pwhite(0.5, 1.5),// switch duration

+

Pseq([0,1],inf), // switch indices

+

[ [], [] ], // default values for help synths

+

// "+" wraps collections, so if ~theseVals is an interval then ~midinote consists of the two added sevenths [-5, 5], [0, 10], 

+

// otherwise ~midinote is a chord of fourths 

+

[ 0.2, [\midinote, Pkey(\theseVals) + [-5, 0, 5,10] , \legato, 0.2, \amp, 0.05 ],

+

    0.1, [\midinote, Pkey(\thisVal) + Pseq([0,1],inf), \legato, 0.2, \amp, 0.08 ] ],

+

  [ Pstutter(Pwhite(5,10), Pxrand([0, 1, \all], inf)), \switch /* single line switches between trill and arpeggio */]

+

).play;  

+

)

+


+

p.free;

+


+


+

//////////////////////////////////////////////////////////////////////////////////

+


+


+

// HSpar with two help synth definitions

+


+

(

+

h = HSpar(s, [ 

+

{ |start = 90, end = 60, dur = 10, add = 0|

+

XLine.kr(start, end, dur) + add; },

+

{ |freq = 0.3, dev = 15, center = 60, phase = 0, add = 0|

+

LFTri.kr(freq, phase, dev, center + add); }

+

]);

+

)

+


+


+

// switch between two help synths

+

// both help synths are run from the start (default hsStartIndices = true)

+

// help synths of switch index are paused when index is left (switchOff: true) and 

+

// resumed when index is given (switchOn: true)

+

// movement downwards needs more than 10 seconds defined by XLine

+


+

(

+

p = PHSpar(h, 

+

Pwhite(0.3,1.0), // switch duration

+

Pseq([0,1], inf), // switch indices,

+

// distinguish help synth values by reference to ~switchIndex

+

pbindArgs: [0.12, [\midinote, Pkey(\val) + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ],

+

switchOn: true,

+

switchOff: true

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// never pause help synth #0, always pause #1

+

// end value of help synth #0 reached after 10 seconds

+


+

(

+

p = PHSpar(h, 

+

Pwhite(0.3,1.0), // switch duration

+

Pseq([0,1], inf), // switch indices,

+

// distinguish help synth values by reference to ~switchIndex

+

pbindArgs: [0.12, [\midinote, Pkey(\val) + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ],

+

switchOn: true,

+

switchOff: Pseq([false, true], inf) // next pause value with next switch index

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// hsStartIndices: define which help synths should be run from the beginning (only #1)

+

// help synth #0 is run when switched first (switchOn: true) 

+

// movement downwards starts after 5 seconds

+


+

(

+

p = PHSpar(h, 

+

Pseq([5, Pwhite(0.3,1.0, inf)]), // switch duration

+

Pseq([1,0], inf), // switch indices,

+

// distinguish help synth values by reference to ~switchIndex

+

pbindArgs: [0.12, [\midinote, Pkey(\val) + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ],

+

switchOn: true,

+

hsStartIndices: 1 // \none (except the switched) or [1] would also do

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// set: determines whether new values should be polled from the streams (defined in helpSynthArgs) at switch time

+

// here only at every second switch a new add value (register change) is set

+


+

(

+

p = PHSpar(h, 

+

Pwhite(0.3, 0.5, inf), // switch duration

+

Pseq([0,1], inf), // switch indices,

+

[ [\add, Pseq([0, 10.5, 21], inf) ], [\add, Pseq([0, 10.5, 21], inf), \dev, 5] ],  // helpSynthArgs

+

// distinguish help synth values by reference to ~switchIndex

+

pbindArgs: [0.12, [\midinote, Pkey(\val) + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ],

+

set: Pstutter(2, Pseq([true, false], inf))  // next set value with next switch index

+

).play;  

+

)

+


+

p.free;

+


+


+


+

// now things quite mixed up

+


+

// basic pitches chosen by index sequence defined in hsIndices, reference by Pkey(\theseVals)

+

// switchIndex only determines the added interval

+

// if theseVals contains only one value the determined interval is based on this value ([a] + [x, y] = [a + x, a + y]), 

+

// otherwise it is just added to the interval of theseVals ([a, b] + [x, y] = [a + x, b + y])  

+


+

// printout of variables which may be used within a PHSpar definition

+

// timeGrains is just a time ID, depending on granularity, not used for scheduling

+


+

(

+

p = PHSpar(h, 

+

Pwhite(0.3,1.0), // switch duration

+

Pseq([0,1], inf), // switch indices,

+

// distinguish added interval by reference to ~switchIndex

+

pbindArgs: [0.12, [

+

\midinote, Pkey(\theseVals) + Pkey(\switchIndex).collect(switch(_, 0, [0, 2.5], 1, [0, 7])) , 

+

\legato, 0.2,

+

\post, Pfunc {|e| e.use {

+

"demandIndex: ".post; ~demandIndex.postln;

+

"timeGrains: ".post; ~timeGrains.postln;

+

"dur: ".post; ~dur.postln;

+

"switchIndex: ".post; ~switchIndex.postln;

+

"vals: ".post; ~vals.postln;

+

"val: ".post; ~val.postln;

+

"theseIndices: ".post; ~theseIndices.postln;

+

"theseVals: ".post; ~theseVals.postln;

+

"thisVal: ".post; ~thisVal.postln;

+

"================================".postln;

+

}

+

}

+

]],

+

hsIndices: [ Pstutter(Pwhite(5,10), Pxrand([ 0, 1, \all ], inf)) ]

+

).play;  

+

)

+


+

p.free;

+


+


+ + diff --git a/Help/PHSparPlayer.html b/Help/PHSparPlayer.html new file mode 100755 index 0000000..f91123c --- /dev/null +++ b/Help/PHSparPlayer.html @@ -0,0 +1,328 @@ + + + + + + + + + + + +

PHSparPlayer (PHelpSynthParPlayer) PHSpar player object

+


+

Part of: miSCellaneous

+


+

Inherits from: PHSusePlayer (PHelpSynthUsePlayer)

+


+

Implicitely instantiated when PHSpar's play method is called, allows stopping and resuming with options also concerning the help synth.

+


+


+

See also: Working with HS and HSpar, HS with VarGui, HSpar, PHSpar, PHSparUse, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (pHelpSynthPar)

+

+

Creates a new PHSparPlayer object.

+

+

pHelpSynthPar - A PHSpar object.

+


+


+


+

Status control

+


+

play(clock, quant, hsPlay, switchPlay, pbindPlay, quantBufferTime)

+

+

clock - A TempoClock object. If not assigned, takes the default TempoClock.

+

quant - Quant or SimpleNumber. Makes the player start at the next grid that gives enough time for latency. 

+

hsPlay - Boolean, Integer or SequenceableCollection of Integers determining help synth indices. 

+

Determines if help synth(s) should play. Defaults to true.

+

switchPlay - Boolean. Determines if switch pattern should play. Defaults to true.

+

pbindPlay - Boolean. Determines if Pbind(s) should play. Defaults to true.

+

quantBufferTime - SimpleNumber (seconds). Calculated time to include latency for "stepping in" 

+

is lengthened by this value. Defaults to 0.2.

+


+


+

stop(hsStop, switchStop, pbindStop, addAction)

+

+

hsStop - Boolean, Integer or SequenceableCollection of Integers determining help synth indices. 

+

Determines if help synth(s) should pause. Defaults to false.

+

switchStop - Boolean. Determines if switch pattern player should pause. Defaults to false.

+

pbindStop - Boolean. Determines if Pbind player(s) should pause. Defaults to true.

+

addAction - Function to be evaluated at receive time.

+


+


+

pause(hsStop, switchStop, pbindStop, addAction)

+

+

= stop

+


+


+

free

+

+

Stop the PHSparPlayer and all PHSusePlayers that are using the same HSpar, also free the HSpar.

+


+


+

Note: stop (= pause) allows resuming the player - free resets, player can be started again. 

+


+


+

Examples

+


+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// define PHSpar and several users 

+


+

(

+

h = HSpar(s, [ 

+

{ |freq = 2, dev = 7, center = 60|

+

LFDNoise3.kr(freq, dev, center) }, 

+

{ |freq = 5, dev = 10, center = 80|

+

LFDNoise3.kr(freq, dev, center) } 

+

]);

+


+

~p1 = PHSpar(h, 

+

pbindArgs: [0.1, [\midinote, Pkey(\thisVal), \legato, 0.2, \amp, 0.06 ] ],

+

hsIndices: [0] );

+


+

~p2 = PHSparUse(h, 

+

pbindArgs: [0.2, [\midinote, Pkey(\thisVal) - 3,\legato, 0.2, \amp, 0.06  ]],

+

hsIndices: [1] );          

+


+

~p3 = PHSparUse(h, 

+

pbindArgs: [Pn(Pshuf([0.2, 0.1, 0.1], 1), inf), [\midinote, Pkey(\theseVals) + 5, \legato, 0.2, \amp, 0.06 ]],

+

hsIndices: [[0, 1]] );          

+


+

~p4 = PHSparUse(h, 

+

pbindArgs: [Pn(Pshuf([0.2, 0.1, 0.1], 1), inf), [\midinote, Pkey(\theseVals) + 8, \legato, 0.2, \amp, 0.06 ]],

+

hsIndices: [[0, 1]] );          

+


+

c = TempoClock.new;

+

q = 0.8;

+

)

+


+


+

// start PHSparPlayer with help synth #0 

+


+

~x1 = ~p1.play(c,q);

+


+


+

// add a PHSusePlayer using help synth #1

+


+

~x2 = ~p2.play(c,q);

+


+


+

// add a PHSusePlayer using both help synths

+


+

~x3 = ~p3.play(c,q);

+


+


+

// and another one

+


+

~x4 = ~p4.play(c,q);

+


+


+

// stop PHSparPlayer, help synths keep playing

+


+

~x1.stop;

+


+


+

// stop a PHSusePlayer

+


+

~x2.stop;

+


+


+

// and another one, only player ~x4 left

+


+

~x3.stop;

+


+


+

// resume ~x1

+


+

~x1.play(c,q);

+


+


+

// stop only help synth #1

+


+

~x1.stop(hsStop: 1, pbindStop: false);

+


+


+

// stop also help synth #0 and player ~x1

+


+

~x1.stop(hsStop: 0);

+


+


+

// now only one pbind engaged via PHSusePlayer ~x4, but help synths may be controlled via PHSparPlayer ~x1 !  

+

// resume both help synths

+


+


+

~x1.play(hsPlay: [0,1], pbindPlay: false);

+


+


+

// stop them again, using keyword

+


+

~x1.stop(hsStop: \all, pbindStop: false);

+


+


+

// stop last remaining PHSusePlayer via the "leading" PHSparPlayer and free HSpar

+


+

~x1.free;

+


+


+


+


+


+

//////////////////////////////////////////////////// 

+


+


+

(

+

// define HSpar: two sine waves with opposite phases

+


+

h = HSpar(s, [ 

+

{ |freq = 0.25, dev = 5, center = 70|

+

SinOsc.kr(freq, 3pi/2, dev, center) }, 

+

{ |freq = 0.25, dev = 5, center = 70|

+

SinOsc.kr(freq, pi/2, dev, center) }

+

]);

+


+

// one stream shared by both switch indices

+

// goal: repetition of sine wave segment, alternate register, small random add for pitch

+


+

~pitchBaseStream = (Pseq([60,80],inf) + Pwhite(0.0,5.0)).asStream;

+


+

p = PHSpar(h, 2, // switchDur = half phase of sine wave

+

Pseq([0,1], inf), // switchIndex

+

[\center, ~pitchBaseStream] ! 2,

+

[0.25, [\midinote, Pkey(\val) + [-5.25, 0, 4, 7.25] , \legato, 0.2, \amp, 0.06 ]]);

+


+

)

+


+


+

// stopping and resuming with options

+

// if stopped together, help synths, pbinds and switchIndex player are kept in sync for resuming

+

// therefore methods stop and play are blocking the player for some moments, but freeing is always possible

+


+

// switchStop = true is blocking for the whole current switch duration - this could be reduced

+


+

x = p.play;

+


+


+

// stop everything, keep sync: try stopping and resuming several times, leave some moments between

+


+

x.stop(switchStop: true, hsStop: true, pbindStop: true);

+


+

x.play;

+


+


+

// free everything

+


+

x.free;

+


+


+


+

////////////////// 

+


+

x = p.play;

+


+


+

// stop only the pbind 

+

// try stopping and resuming several times - always ascending segments of the sine wave, pbind is "stepping in"

+

// as points of stepping in may differ, low slope in ascending sequences may occur at the beginning or at the end 

+


+

x.stop;  // equivalent to x.stop(switchStop: false, hsStop: false, pbindStop: true)

+


+

x.play;

+


+


+

//

+


+

x.free;

+


+


+


+

////////////////// 

+


+

x = p.play;

+


+


+

// stop everything BUT the pbind 

+

// try stopping and resuming several times - again always ascending segments of the sine wave as

+

// switchIndex player and help synths are stopped and started together

+


+

x.stop(switchStop: true, hsStop: true, pbindStop: false);

+


+

x.play;

+


+


+

//

+


+

x.free;

+


+


+


+

////////////////// 

+


+

x = p.play;

+


+


+

// let only help synths run

+

// try stopping and resuming several times

+

// switchIndex player and help synths are relinked, other sine wave segments establish

+


+

x.stop(switchStop: true, hsStop: false, pbindStop: true);

+


+

x.play;

+


+


+

//

+


+

x.free;

+


+


+ + diff --git a/Help/PHSparUse.html b/Help/PHSparUse.html new file mode 100644 index 0000000..6fe09c7 --- /dev/null +++ b/Help/PHSparUse.html @@ -0,0 +1,222 @@ + + + + + + + + + + + +

PHSparUse (PHelpSynthParUse) defines Pbind(s) for using synth values of a HSpar

+


+

Part of: miSCellaneous

+


+

Inherits from: PHSuse (PHelpSynthUse)

+


+

Defines Pbind(s) which, when played, can use values of synths derived from HSpar's synth definitions. Playing a PHSparUse is just an option for using an already playing help synth of a HSpar, which requires PHSpar first. See Working with HS and HSpar, paragraph "Working Scheme". 

+


+

See also: Working with HS and HSpar, HS with VarGui, HSpar, PHSpar, PHSparPlayer, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (helpSynth, pbindArgs, hsIndices)

+

+

Creates a new PHSparUse object.

+

+

helpSynth - A HSpar object.

+

pbindArgs - Collection of the form [ dur1, pbindData1, ... , durN, pbindDataN ] , with

+

dur i - Duration value or pattern / stream of durations for corresponding Pbind(s).

+

pbindData i - A collection of Pbind pairs or a collection of Pbind pair collections,

+

defining possibly several Pbinds with same event timing. 

+

hsIndices - Per default values are taken from the currently switched help synth.

+

Explicitely given hsIndices allow reference to values of other help synths from the corresponding Pbind(s). 

+

Expects a collection of valid hsIndex values resp. patterns / streams of valid hsIndex values.

+

A valid hsIndex value is a valid help synth index or a collection of valid help synth indices.

+


+


+

Status control

+


+

play(clock, quant)

+

+

A PHSusePlayer object is instantiated and started using the TempoClock clock. 

+

Quant or SimpleNumber quant lets the player step into the quantization as soon as possible, 

+

with respect to the necessary latency. The PHSusePlayer can be stopped and resumed with options.

+


+


+

Examples

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// HSpar with two synth definitions

+


+

(

+

h = HSpar(s, [ { |freq = 1, dev = 10, center = 80|

+

LFDNoise3.kr(freq, dev, center) },

+

{ |freq = 0.5, dev = 5, center = 60, addFreq = 0.1, addDev = 5|

+

LFDNoise3.kr(freq, dev, center) + SinOsc.kr(addFreq, 0, addDev) } 

+

]);

+

+

c = TempoClock(1);

+

q = 0.12;

+

)

+


+


+

// Play Pbind (via PHSpar) to poll values from one or both synths, according to the pattern given to hsIndices. 

+

// Random add with adverb "+.x" adds an interval also to each of two simultaneous synth values.

+


+

(

+

x = PHSpar(h, 

+

pbindArgs: [0.12, [\midinote, Pkey(\theseVals).collect(_ +.x [7, 8, [0,7], [-1,8]].choose), 

+

\legato, 0.2, \amp, 0.05 ]],

+

hsIndices: [ Prand([0,1,\all], inf)] 

+

).play(c,q);

+

)

+


+


+

// "stepping in" with second player at (with respect to latency) next possible time on grid

+


+

(

+

y = PHSparUse(h, 

+

pbindArgs: [ Prand([0.36, 0.48],inf),  

+

[\midinote, Pkey(\theseVals) + [1, 1.75, 2.5, 3.25, 4, 4.75, 5.5, 6.25], 

+

\legato, 0.2, \amp, Prand([0.03, 0.05, 0.07], inf) ]],

+

hsIndices:  [ Pn(Pshuf([0,0,1,1],1), inf) ]

+

).play(c,q);

+

)

+


+


+

// stop x, help synths still playing, producing values for y

+


+

x.stop;

+


+


+

// resume x 

+


+

x.play(c,q);

+


+


+

// freeing the PHSplayer also stops all "related" PHSusePlayers and frees the HS

+


+

x.free;

+


+


+


+

/////////////////////////////////////////////////////////////////////////////////

+


+

// Instead of using PHSuse / PHSparUse objects in order to have seperate players  

+

// it's, of course, also possible to define several HS / HSpar objects independently.

+

// As before players can be synced by Quants.

+


+

(

+

h = HSpar(s, [ 

+

{ |freq = 0.5, dev = 5, center = 70| 

+

LFDNoise3.kr(freq, dev, center) },

+

{ |freq = 0.2, dev = 5, center = 62, addFreq = 0.1, addDev = 2|

+

LFTri.kr(freq, 0, dev, center) + SinOsc.kr(addFreq, 0, addDev) } 

+

]);

+

c = TempoClock.new;

+

q = 0.24;

+

)

+


+


+

// first player using a HSpar

+


+

(

+

x = PHSpar(h, 

+

pbindArgs: [

+

Pstutter(Pwhite(5,10), Pseq([0.12, 0.16], inf)),

+

[\midinote, Pkey(\thisVal) + Pseq([[2, 5], [1, 6], [0, 7]], inf), \legato, 0.2, \amp, 0.07], 

+

0.24, [\midinote, Pkey(\thisVal) + [-6, -1, 3], \legato, 0.2, \amp, 0.07]],

+

hsIndices: [0, 1]

+

).play(c,q);  

+

)

+


+


+

// define an additional HS 

+


+

(

+

k = HS(s, {|start = 90, end = 50, dur = 10| XLine.kr(start, end, dur); });

+

)

+


+


+

// start synced player 

+


+

(

+

r = PHS(k, 

+

[\start, { rrand(85, 100) }], 

+

0.12, [\midinote, Pkey(\val) + [0, 3.5], \legato, 0.2, \amp, 0.07]

+

);

+

y = r.play(c,q);  

+

)

+


+


+

// stop and free (reset) second player and HS  

+


+

y.free;

+


+


+

// play again - a new help synth is started

+


+

y.play(c,q);

+


+


+

// stop and free first player and HSpar 

+


+

x.free;

+


+


+

// stop and free second one and HS 

+


+

y.free;

+


+ + diff --git a/Help/PHSplayer.html b/Help/PHSplayer.html new file mode 100755 index 0000000..0955beb --- /dev/null +++ b/Help/PHSplayer.html @@ -0,0 +1,145 @@ + + + + + + + + + + + +

PHSplayer (PHelpSynthPlayer) PHS player object

+


+

Part of: miSCellaneous

+


+

Inherits from: PHSusePlayer (PHelpSynthUsePlayer)

+


+

Implicitely instantiated when PHS's play method is called, allows stopping and resuming with options also concerning the help synth.

+


+


+

See also: Working with HS and HSpar, HS with VarGui, HS, PHS, PHSuse, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (pHelpSynth)

+

+

Creates a new PHSplayer object.

+

+

pHelpSynth - A PHS object.

+


+


+


+

Status control

+


+

play(clock, quant, hsPlay, pbindPlay, quantBufferTime)

+

+

clock - A TempoClock object. If not assigned, takes the default TempoClock.

+

quant - Quant or SimpleNumber. Makes the player start at the next grid that gives enough time for latency. 

+

hsPlay - Boolean. Determines if help synth should also start. Defaults to true.

+

pbindPlay - Boolean. Determines if Pbind(s) should play. Defaults to true.

+

quantBufferTime - SimpleNumber (seconds). Calculated time to include latency for "stepping in" 

+

is lengthened by this value. Defaults to 0.2.

+


+


+

stop(hsStop, pbindStop, addAction)

+

+

hsStop - Boolean. Determines if help synth should stop. Defaults to false.

+

pbindStop - Boolean. Determines if Pbind player(s) should stop. Defaults to true.

+

addAction - Function to be evaluated at receive time.

+


+


+

pause(hsStop, pbindStop, addAction)

+

+

= stop

+


+


+

free

+

+

Stop the PHSplayer and all PHSusePlayers that are using the same HS, also free the HS.

+


+


+

Note: stop (= pause) allows resuming the player - free resets, player can be started again. 

+


+


+

Examples

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// define HS, PHS - play

+


+

(

+

h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) });

+


+

p = PHS(h, nil, // default help synth args

+

Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val), \amp, 0.1  ],

+

0.1, [ \midinote, Pkey(\val) + 9.5 + Pxrand([0, 2, 5],inf), \amp, 0.08 ]

+

).play;

+

)

+


+


+

// stop only help synth

+


+

p.stop(hsStop: true, pbindStop: false);

+


+


+

// stop pbind

+


+

p.stop;

+


+


+

// resume help synth and eventstream player

+


+

p.play(hsPlay: true, pbindPlay: true);

+


+


+

// stop player and free HS

+


+

p.free;

+


+


+ + diff --git a/Help/PHSuse.html b/Help/PHSuse.html new file mode 100755 index 0000000..e89b8b1 --- /dev/null +++ b/Help/PHSuse.html @@ -0,0 +1,169 @@ + + + + + + + + + + + +

PHSuse (PHelpSynthUse) defines Pbind(s) for using synth values of a HS

+


+

Part of: miSCellaneous

+


+

Inherits from: Object

+


+

Defines Pbind(s) which, when played, can use values of a synth derived from HS's synth definition. Playing a PHSuse is just an option for using an already playing help synth of a HS, which requires PHS first. See Working with HS and HSpar, paragraph "Working Scheme". 

+


+

See also: Working with HS and HSpar, HS with VarGui, HS, PHS, PHSplayer, PHSusePlayer

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (helpSynth, dur1, pbindData1, ... , durN, pbindDataN)

+

+

Creates a new PHSuse object.

+

+

helpSynth - A HS object.

+

dur i - Duration value or pattern / stream of durations for corresponding Pbind(s).

+

pbindData i - A collection of Pbind pairs or a collection of Pbind pair collections,

+

defining possibly several Pbinds with same event timing. 

+


+


+

Status control

+


+

play(clock, quant)

+

+

A PHSusePlayer object is instantiated and started using the TempoClock clock. 

+

Quant or SimpleNumber quant lets the player step into the quantization as soon as possible, 

+

with respect to the necessary latency. The PHSusePlayer can be stopped and resumed with options.

+


+


+

VarGui support

+


+

asTask(clock, quant, newEnvir, removeCtrWithCmdPeriod)

+

+

Returns a wrapper Task, which may be passed to a VarGui object. 

+

Playing and stopping the wrapper Task invokes playing and 

+

stopping behaviour of the underlying PHSusePlayer. See HS with VarGui for examples.

+

+

clock - TempoClock.

+

quant - Quant or SimpleNumber.

+

newEnvir - Boolean. Determines if Task will be played in a newly generated environment. Defaults to true.

+

This option especially becomes important when PHSuse's pbindData contains functional code with 

+

environmental variables.

+

removeCtrWithCmdPeriod - Boolean. Defaults to true. 

+

Determines if notification of PHSusePlayer will be stopped with CmdPeriod.

+


+


+

Examples

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// two Pbinds getting values for pitches from a single HS

+


+

h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) });

+


+


+

// define Pbinds via PHS and PHSuse separately, 

+

// choose quant that allows synchronization 

+


+

(

+

u = PHS(h, nil, // default help synth args

+

0.15, [ \midinote, Pkey(\val) + [-5, 0], \amp, 0.065 ]);

+


+

v = PHSuse(h, 0.15, 

+

[ \midinote, 130 - Pkey(\val) + [0, 5] /* mirror at center frequency */,

+

  \amp, Pwrand([0.03, 0.07], [0.7, 0.3], inf) ]);

+

+

c = TempoClock(1);

+

q = 0.3;

+

)

+


+


+

// start first player

+


+

x = u.play(c,q);

+


+


+

// "stepping in" with second player at (with respect to latency) next possible time on grid

+


+

y = v.play(c,q);

+


+


+

// stop x, help synth still playing, producing values for y

+


+

x.stop;

+


+


+

// define and play another PHSuse

+


+

(

+

w = PHSuse(h, 0.15, 

+

[ \midinote, 130 - Pkey(\val) + [0, 5] + Pwhite(7.0, 10.0) /* mirror at center frequency + random add */,

+

  \amp, Pwrand([0.03, 0.07], [0.7, 0.3], inf) ]);

+


+

z = w.play(c,q);

+

)

+


+


+

// resume x 

+


+

x.play(c,q);

+


+


+

// freeing the PHSplayer also stops all "related" PHSusePlayers and frees the HS

+


+

x.free;

+


+


+


+


+ + diff --git a/Help/PHSusePlayer.html b/Help/PHSusePlayer.html new file mode 100755 index 0000000..b2501d3 --- /dev/null +++ b/Help/PHSusePlayer.html @@ -0,0 +1,156 @@ + + + + + + + + + + + +

PHSusePlayer (PHelpSynthUsePlayer) player object for PHSuse and PHSparUse 

+


+

Part of: miSCellaneous

+


+

Inherits from: Object

+


+

Implicitely instantiated when PHSuse's or PHSparUse's play method is called.

+


+


+

See also: Working with HS and HSpar, HS with VarGui, PHSuse, PHSparUse

+


+


+

Some Important Issues

+


+

See Working with HS and HSpar

+


+


+

Creation / Class Methods

+


+

*new (pHelpSynthUse)

+

+

Creates a new PHSusePlayer object.

+

+

pHelpSynthUse - A PHSuse or PHSparUse object.

+


+


+


+

Status control

+


+

play(clock, quant, quantBufferTime)

+

+

clock - A TempoClock object. If not assigned, takes the default TempoClock.

+

quant - Quant or SimpleNumber. Makes the player start at the next grid that gives enough time for latency. 

+

quantBufferTime - SimpleNumber (seconds). Calculated time to include latency for "stepping in" 

+

is lengthened by this value. Defaults to 0.2.

+


+


+

stop(addAction)

+

+

addAction - Function to be evaluated at receive time.

+


+


+

pause(addAction)

+

+

= stop

+


+


+

free

+

+

Only free this PHSusePlayer - the PHSplayer / PHSparPlayer, which is using the same HS / HSpar, is not affected.

+


+


+

Note: stop (= pause) allows resuming the player - free resets, player can be started again. 

+


+


+


+

Examples

+


+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// define HS, PHS, PHSuse

+


+

(

+

h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) });

+


+

u = PHS(h, nil, // default help synth args

+

// two pbinds with different timing

+

Prand([0.4, 0.2],inf) , [ \midinote, Pkey(\val) + 4, \amp, 0.07  ],

+

0.1, [ \midinote, Pkey(\val) + 15 + Pxrand([0, 2, 5],inf), \amp, 0.04, \legato, 0.5 ]

+

);

+

+

v = PHSuse(h, // two pbinds with different timing

+

Prand([0.4, 0.2],inf) , [ \midinote, Pkey(\val), \amp, 0.07  ],

+

0.1, [ \midinote, Pkey(\val) + 6 + Pxrand([0, 2, 5],inf), \amp, 0.06, \legato, 0.5  ]

+

);

+

+

c = TempoClock(1);

+

q = 0.2;

+

)

+


+


+

// play PHS

+


+

x = u.play(c,q);

+


+


+

// play PHSuse

+


+

y = v.play(c,q);

+


+


+

// stop PHSplayer

+


+

x.stop;

+


+


+

// PHSusePlayer doesn't control HS - HS synth still running, see server window

+


+

y.free;

+


+


+

// PHSplayer controls HS - this also stops HS synth   

+


+

x.free;

+


+


+ + diff --git a/Help/PIdev.html b/Help/PIdev.html new file mode 100755 index 0000000..a9a7d54 --- /dev/null +++ b/Help/PIdev.html @@ -0,0 +1,342 @@ + + + + + + + + + + + +

PIdev pattern searching for numbers with integer distance from a source pattern, optionally avoiding repetitions within a span

+


+

Part of: miSCellaneous

+


+

Inherits from: Pattern

+


+

DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples.

+

 

+

NOTE: It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples.

+


+

NOTE: In contrast to DIdev, PIdev and PLIdev do *not* need to know maximum deviations (minLoDev, maxHiDev) beforehand. Thus the order of arguments is different (here loDev and hiDev before lookBack).

+


+

See also: Idev suite, PLIdev, DIdev

+


+


+

Creation / Class Methods

+


+

Creates a new PIdev object.

+

+

*new (pattern, maxLookBack = 3, loDev = -3, hiDev = 3, lookBack, thr = 1e-3, length = inf)

+

+

pattern - The source value pattern to start search from.

+

maxLookBack - Integer, the maximum lookback span. Fixed, defaults to 3.

+

loDev - Determines the current low deviation for the search. Defaults to -3.

+

hiDev - Determines the current high deviation for the search. Defaults to 3.

+

lookBack - Determines the current lookback span for avoiding repetitions.

+

Can be modulated but must not exceed maxLookBack.

+

If no value is passed, then maxLookBack is taken.

+

thr - Threshold for equality comparison. Can be modulated, defaults to 1e-3. 

+

length - Number of repeats. Defaults to inf. 

+

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Ex.1) Basic usage: random choice within region without repetitions

+

+

// constant source (72), max deviation +/- 3

+

// no repetition within 5 pitches

+


+

(

+

p = Pbind(

+

\dur, 0.2,

+

\midinote, PIdev(72, 5, -3, 3).trace(prefix: "midi "),

+

).play;

+

)

+


+

p.stop

+


+


+


+

Ex.2) Variable deviations and lookBack

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

~lookBack = 2;

+


+

p = Pbind(

+

\dur, 0.2,

+

\midinote, PIdev(72, 11, Pfunc { ~loDev }, Pfunc { ~hiDev }, Pfunc { ~lookBack }).trace(prefix: "midi "),

+

).play;

+

)

+


+

// change on the fly

+

// as lookBack equals 2, this defines a fixed sequence (up or down anyway)

+


+

(

+

~loDev = -1;

+

~hiDev = 1;

+

)

+


+

// widen range

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

)

+


+

// force a twelve-tone row

+


+

~lookBack = 11;

+


+


+

// contradictory input, lookBack 11 not possible within range, causes repetitions

+


+

(

+

~loDev = -3;

+

~hiDev = 2;

+

)

+


+

p.stop

+


+


+


+

Ex.3) Moving source signal

+


+

(

+

~loDev = -1;

+

~hiDev = 1;

+

~lookBack = 2;

+


+

p = Pbind(

+

\dur, 1/7,

+

\midinote, PIdev(

+

Pseg(Pseq([65, 90], inf), 5, \sin).round,

+

11,

+

Pfunc { ~loDev },

+

Pfunc { ~hiDev },

+

Pfunc { ~lookBack }

+

).trace(prefix: "midi "),

+

).play;

+

)

+


+

// widen range and increase lookBack

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

~lookBack = 10;

+

)

+


+

p.stop;

+


+


+

Ex.4) Dynamic deviation range and lookBack

+


+

// lookBack and deviations coupled here

+

// maxLookBack must be large enough

+


+

(

+

~loDev = -1;

+

~hiDev = 1;

+

~lookBack = 2;

+


+


+

p = Pbind(

+

    \dur, 1/7,

+

    \midinote, PIdev(

+

        78,

+

        10,

+

        Pn(Plazy { ~loDev }),

+

        Pn(Plazy { ~hiDev }).trace(prefix: "absolute deviation "),

+

        Pn(Plazy { ~lookBack })

+

    ).trace(prefix: "midi ");

+

).play

+

)

+


+

// start parameter movement on the fly

+


+

(

+

~loDev = Pseg(Pseq([2, 5].neg, inf), 5, \sin);

+

~hiDev = Pseg(Pseq([2, 5], inf), 5, \sin).trace(prefix: "absolute deviation and lookBack ");

+

~lookBack = Pseg(Pseq([2, 5], inf), 5, \sin);

+

)

+


+

p.stop

+


+


+


+

Ex.5) Non-integer source

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

~lookBack = 3;

+

~thr = 1;

+


+

p = Pbind(

+

\dur, 1/7,

+

\midinote, PIdev(

+

Pseg(Pseq([65, 90], inf), 5, \sin),

+

5,

+

Pfunc { ~loDev },

+

Pfunc { ~hiDev },

+

Pfunc { ~lookBack },

+

Pfunc { ~thr }

+

).trace(prefix: "midi "),

+

).play;

+

)

+


+

// close floats can occur here

+

~thr = 0.01

+


+

// not here

+

~thr = 2

+


+


+

p.stop

+


+


+
Ex.6) Multichannel expansion

+

 

+

// larger pitch range and lookBack in upper voice, 

+

// as with most patterns, no automatic array expansion of pattern arguments

+


+

(

+

p = Pbind(

+

\dur, 1/7,

+

\src, Pseg(Pseq([65, 85], inf), 5, \sin).round,

+

\midinote, Ptuple([

+

PIdev(Pkey(\src), 1, -1, 1),

+

PIdev(Pkey(\src) + 8.5, 3, -5, 5)

+

]).trace(prefix: "midi "),

+

).play;

+

)

+


+

p.stop

+


+


+

Ex.7) Application to other params: rhythm

+

 

+

// if we have indexed data of whatever, we can slide over it,

+

// groups of durations as items to be streamed by PIdev

+


+

(

+

~rhythmBase = [

+

[1, 1],

+

[2, 1, 1],

+

[1, 1, 2]

+

].collect(_.normalizeSum);

+


+

~rhythms = ~rhythmBase *.x [1, 2];

+

~rhythmNum = ~rhythms.size;

+

~rhythms = ~rhythms.scramble;

+


+

SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, 

+

rq = 0.05, pan = 0, amp = 0.1|

+

var sig = { WhiteNoise.ar } ! 2;

+

sig = BPF.ar(sig, freq, rq) *

+

EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

(rq ** -1) * (250 / (freq ** 0.8));

+

OffsetOut.ar(out, Pan2.ar(sig, pan));

+

}).add;

+

)

+


+

(

+

// rhythmic variation and partial pitch repetition

+

// play for a while to note slow sliding caused by Pseg

+


+

~loDev = -1;

+

~hiDev = 1;

+


+

p = Pbind(

+

\instrument, \noise_grain,

+

\rel, Pexprand(0.05, 0.15),

+

\dur, PIdev(

+

// be careful not to exceed index bounds

+

Pseg(Pseq([~loDev.abs, ~rhythmNum - ~hiDev - 1], inf), 10, \sin, inf).round, 

+

2, // lookBack span, no repetition within 3 items

+

~loDev, 

+

~hiDev

+

).trace(prefix: "rhythm type: ").collect(~rhythms[_]).flatten * 0.3,

+

\midinote, Pstutter(Pwhite(1, 2), Pclump(3, Pxrand((50..100), inf))).flatten + [0, 12],

+

\pan, Pstutter(Pwhite(1, 2), Pclump(3, Pwhite(-1.0, 1))).flatten

+

).play;

+

)

+


+

p.stop

+


+


+


+

Ex.8) Proof of concept

+


+

(

+

// Function to check an array for repetitions within a maximum test span

+


+

~repetitionCheck = { |array, maxTestSpan|

+

maxTestSpan.do { |i|

+

var result = (array.drop(i+1) - array).drop((i+1).neg).includes(0).not;

+

("no repetitions within a span of " ++ (i+2).asString ++ " items: ").post;

+

result.postln;

+

}

+

}

+

)

+


+

// test case

+

// no repetitions within a maximum span of 6 (lookBack == 5)

+


+

(

+

p = PIdev(Pbrown(0, 20, 0.3).round.asInteger, 5, -7, 7).iter;

+

a = p.nextN(10000);

+

a.plot;

+

~repetitionCheck.(a, 10);

+

)

+


+


+

 

+


+


+ + diff --git a/Help/PL.html b/Help/PL.html new file mode 100755 index 0000000..bdcd270 --- /dev/null +++ b/Help/PL.html @@ -0,0 +1,173 @@ + + + + + + + + + + + +

PL dynamic scope placeholder pattern 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_Pattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+

NOTE: PL follows a paradigm of immediate replacement. There are cases though where you might prefer to finish streams or substreams before replacement, especially when syncing comes into play, for these options consider PLn and the cutItems arg of PLx list patterns.

+


+

See also: PLn, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (item, repeats, type, envir)

+

+

Creates a new PL object.

+

+

item - Symbol or other Object. 

+

If a Symbol is passed, item can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

type - Expects 1 or inf. 

+

Defines how items other than Patterns or Streams should be embedded.

+

Defaults to 1. Rather to be used by other PLx Patterns than by the user.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

p = Pbind(\midinote, PL(\a), \dur, 0.2);

+


+


+

// prepare current Environment

+


+

(

+

~a = 60;

+

x = p.play;

+

)

+


+


+

// replace with items or patterns

+


+

~a = 58;

+


+


+

// PL had repeats = inf, so Pseq is embedded endlessly

+


+

~a = Pseq([60, 60, 58, 60, 53, 54.5, 56, 58]);

+


+

x.stop;

+


+


+

//////////////////////

+


+


+

// placeholder may also get event patterns

+


+

(

+

p = PL(\a, 1);

+


+

~a = Pbind(

+

\midinote, Pwhite(80, 85),

+

\dur, 0.2

+

);

+


+

x = p.play;

+

)

+


+


+


+

// replace, PL had repeats = 1, so ... 

+


+

(

+

~a = Pbind(

+

\midinote, Pseq((70..65)),

+

\dur, 0.05

+

);

+

)

+


+


+

//////////////////////

+


+


+

// PL may be used in cases where there is no PLx implementation

+


+

// Pseg used for pitch curve, linear interpolation 

+


+

(

+

p = Pbind(

+

\midinote, Pseg(PL(\p), PL(\d), \lin, inf),

+

\dur, 0.1

+

);

+


+

~p = Pshuf((50..75));

+


+

~d = 0.2;

+


+

x = p.play;

+

)

+


+


+

// play with segment length

+


+

~d = 0.4;

+


+

~d = 1;

+


+


+

// can also be replaced by pattern

+


+

~d = Pseq([0.2, 0.4, 1]);

+


+


+

// only two points left for interpolation 

+

// there may be repetitions 

+


+

~p = Pshufn([50, 100]).trace;

+


+

x.stop;

+


+


+ + diff --git a/Help/PLIdev.html b/Help/PLIdev.html new file mode 100755 index 0000000..7d7f4f8 --- /dev/null +++ b/Help/PLIdev.html @@ -0,0 +1,381 @@ + + + + + + + + + + + +

PLIdev dynamic scope pattern searching for numbers with integer distance from a source pattern, optionally avoiding repetitions within a span

+


+

Part of: miSCellaneous

+


+

Inherits from: Pattern

+


+

DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples.

+

 

+

NOTE: It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples.

+


+

NOTE: In contrast to DIdev, PIdev and PLIdev do *not* need to know maximum deviations (minLoDev, maxHiDev) beforehand. Thus the order of arguments is different (here loDev and hiDev before lookBack).

+


+

See also: PLx suite, Idev suite, PIdev, DIdev

+


+


+

Creation / Class Methods

+


+

Creates a new PLIdev object.

+

+

*new (pattern, maxLookBack = 3, loDev = -3, hiDev = 3, lookBack, thr = 1e-3, length = inf, envir = \current)

+

+

pattern - Symbol or PIdev pattern arg. The source value pattern to start search from. 

+

If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. 

+

Can be dynamically replaced by Patterns or Streams.

+

maxLookBack - Integer, the maximum lookback span. Fixed, defaults to 3.

+

loDev - Symbol or PIdev loDev arg. Determines the current low deviation for the search. 

+

If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. 

+

Can be dynamically replaced by Patterns or Streams. Defaults to -3.

+

hiDev - Symbol or PIdev hiDev arg. Determines the current high deviation for the search. 

+

If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. 

+

Can be dynamically replaced by Patterns or Streams. Defaults to 3.

+

lookBack - Symbol or PIdev lookBack arg. Determines the current lookback span for avoiding repetitions.

+

Can be modulated but must not exceed maxLookBack.

+

If no value is passed, then maxLookBack is taken.

+

If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. 

+

Can be dynamically replaced by Patterns or Streams. Defaults to nil.

+

thr - Symbol or PIdev thr arg. Threshold for equality comparison. 

+

If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. 

+

Can be dynamically replaced by Patterns or Streams. Defaults to 1e-3. 

+

length - Symbol or PIdev length arg. Number of repeats. 

+

If a Symbol is passed, a value can be assigned to an envir variable later on. Defaults to inf. 

+

envir - Dictionary or one of the Symbols \top, \t (topEnvironment), \current, \c (currentEnvironment). 

+

Dictionary to be taken for variable reference. Defaults to \current.

+

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

Ex.1) Basic usage: random choice within region without repetitions

+

+

// constant source, max deviation +/- 3

+

// no repetition within 5 pitches

+


+

(

+

~in = 72;

+


+

p = Pbind(

+

\dur, 0.2,

+

\midinote, PLIdev(\in, 5, -3, 3).trace(prefix: "midi "),

+

).play;

+

)

+


+

// change source

+


+

~in = 65

+


+

p.stop

+


+


+

Ex.2) Variable deviations and lookBack

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

~lookBack = 2;

+


+

p = Pbind(

+

\dur, 0.2,

+

\midinote, PLIdev(72, 11, \loDev, \hiDev, \lookBack).trace(prefix: "midi "),

+

).play;

+

)

+


+


+

// change on the fly

+

// as lookBack equals 2, this defines a fixed sequence (up or down anyway)

+


+

(

+

~loDev = -1;

+

~hiDev = 1;

+

)

+


+


+

// widen range

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

)

+


+


+

// force a twelve-tone row

+


+

~lookBack = 11;

+


+


+

// contradictory input, lookBack 11 not possible within range, causes repetitions

+


+

(

+

~loDev = -3;

+

~hiDev = 2;

+

)

+


+

p.stop

+


+


+


+

Ex.3) Moving source signal

+


+

(

+

~loDev = -1;

+

~hiDev = 1;

+

~lookBack = 2;

+


+

p = Pbind(

+

\dur, 1/7,

+

\midinote, PLIdev(

+

Pseg(Pseq([65, 90], inf), 5, \sin).round,

+

11,

+

\loDev, 

+

\hiDev, 

+

\lookBack

+

).trace(prefix: "midi "),

+

).play;

+

)

+


+


+

// widen range and increase lookBack

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

~lookBack = 10;

+

)

+


+

p.stop

+


+


+


+

Ex.4) Dynamic deviation range and lookBack

+


+

// lookBack and deviations coupled here

+

// maxLookBack must be large enough

+


+

(

+

~loDev = -1;

+

~hiDev = 1;

+

~lookBack = 2;

+


+

p = Pbind(

+

\dur, 1/7,

+

\midinote, PLIdev(78, 10, \loDev, \hiDev, \lookBack).trace(prefix: "midi "),

+

).play;

+

)

+


+

// start parameter movement on the fly

+


+

(

+

~loDev = Pseg(Pseq([2, 5].neg, inf), 5, \sin);

+

~hiDev = Pseg(Pseq([2, 5], inf), 5, \sin).trace(prefix: "absolute deviation and lookBack ");

+

~lookBack = Pseg(Pseq([2, 5], inf), 5, \sin);

+

)

+


+

p.stop

+


+


+

Ex.5) Non-integer source

+


+

(

+

~loDev = -6;

+

~hiDev = 5;

+

~lookBack = 3;

+

~thr = 1;

+


+

p = Pbind(

+

\dur, 1/7,

+

\midinote, PLIdev(

+

Pseg(Pseq([65, 90], inf), 5, \sin),

+

5,

+

\loDev,

+

\hiDev,

+

\lookBack,

+

\thr

+

).trace(prefix: "midi "),

+

).play;

+

)

+


+


+

// close floats can occur here

+

~thr = 0.01

+


+


+

// not here

+

~thr = 2

+


+

p.stop

+


+


+
Ex.6) Multichannel expansion

+

 

+

// larger pitch range and lookBack in upper voice 

+

// as with most patterns, no automatic array expansion of pattern arguments

+


+

(

+

~src = Pseg(Pseq([65, 85], inf), 5, \sin).round;

+


+

p = Pbind(

+

\dur, 1/7,

+

\midinote, Ptuple([

+

PLIdev(\src, 1, -1, 1),

+

PLIdev(\src, 3, -5, 5) + 8.5

+

]).trace(prefix: "midi "),

+

).play;

+

)

+


+

p.stop

+


+


+

Ex.7) Application to other params: rhythm

+

 

+

// if we have indexed data of whatever, we can slide over it,

+

// groups of durations as items to be streamed by PLIdev

+


+

(

+

~rhythmBase = [

+

[1, 1],

+

[2, 1, 1],

+

[1, 1, 2]

+

].collect(_.normalizeSum);

+


+

~rhythms = ~rhythmBase *.x [1, 2];

+

~rhythmNum = ~rhythms.size;

+

~rhythms = ~rhythms.scramble;

+


+

SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1,

+

rq = 0.05, pan = 0, amp = 0.1|

+

var sig = { WhiteNoise.ar } ! 2;

+

sig = BPF.ar(sig, freq, rq) *

+

EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

(rq ** -1) * (250 / (freq ** 0.8));

+

OffsetOut.ar(out, Pan2.ar(sig, pan));

+

}).add;

+

)

+


+

(

+

// rhythmic variation and partial pitch repetition

+

// play for a while to note slow sliding, caused by Pseg

+


+

~loDev = -1;

+

~hiDev = 1;

+

~maxLookBack = 5; // fixed !

+

~lookBack = 2;

+


+

// be careful not to exceed index bounds

+

~src = Pseg(Pseq([~loDev.abs, ~rhythmNum - ~hiDev - 1], inf), 10, \sin, inf).round;

+


+

p = Pbind(

+

\instrument, \noise_grain,

+

\rel, Pexprand(0.05, 0.15),

+

\dur, PLIdev(\src, ~maxLookBack, \loDev, \hiDev, \lookBack).trace(prefix: "rhythm type: ")

+

.collect(~rhythms[_]).flatten * 0.3,

+

\midinote, Pstutter(Pwhite(1, 2), Pclump(3, Pxrand((50..100), inf))).flatten + [0, 12],

+

\pan, Pstutter(Pwhite(1, 2), Pclump(3, Pwhite(-1.0, 1))).flatten

+

).play;

+

)

+


+


+

// more variation by larger deviation from fixed source and larger lookBack

+


+

(

+

~src = 3;

+

~loDev = -3;

+

~hiDev = 2;

+

~lookBack = 4;

+

)

+


+


+

// fixed cycle with these bounds and lookBack == 1

+


+

(

+

~loDev = -1;

+

~hiDev = 0;

+

~lookBack = 1;

+

)

+


+

// other fixed cycle

+


+

~src = 2;

+


+

p.stop

+


+


+


+

Ex.8) Proof of concept

+


+

(

+

// Function to check an array for repetitions within a maximum test span

+


+

~repetitionCheck = { |array, maxTestSpan|

+

maxTestSpan.do { |i|

+

var result = (array.drop(i+1) - array).drop((i+1).neg).includes(0).not;

+

("no repetitions within a span of " ++ (i+2).asString ++ " items: ").post;

+

result.postln;

+

}

+

}

+

)

+


+

// test case

+

// no repetitions within a maximum span of 6 (maxLookBack == 5)

+


+

(

+

~src = Pbrown(0, 20, 0.3).round.asInteger;

+

p = PLIdev(\src, 5, -7, 7).iter;

+

a = p.nextN(10000);

+

a.plot;

+

~repetitionCheck.(a, 10);

+

)

+


+


+

 

+ + diff --git a/Help/PLbeta.html b/Help/PLbeta.html new file mode 100755 index 0000000..ca73742 --- /dev/null +++ b/Help/PLbeta.html @@ -0,0 +1,140 @@ + + + + + + + + + + + +

PLbeta dynamic scope Pbeta variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pbeta

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pbeta, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, prob1, prob2, length, envir)

+

+

Creates a new PLbeta object.

+

+

lo - Symbol or Pbeta lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Pbeta hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

prob1 - Symbol or Pbeta prob1 arg. Defaults to 1.

+

If a Symbol is passed, prob1 can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

prob2 - Symbol or Pbeta prob2 arg. Defaults to 1.

+

If a Symbol is passed, prob2 can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pbeta length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\midinote, PLbeta(\lo, \hi, \p1, \p2),

+

\dur, 0.1

+

);

+

)

+


+

// prepare current Environment

+

// prob values for equal distribution

+


+

(

+

~lo = 60;

+

~hi = 90;

+

~p1 = 1;

+

~p2 = 1;

+

)

+


+


+

// run

+


+

x = p.play;

+


+


+

// replace probabilities, get values close to the bounds

+


+

(

+

~p1 = 0.02;

+

~p2 = 0.02;

+

)

+


+


+

// change between close-to-bounds and equally-distributed

+

// PLseq defaults to repeats = inf

+


+

(

+

~p1 =  Pstutter(10, PLseq([0.01, 1]));

+

~p2 =  Pstutter(10, PLseq([0.01, 1]));

+

)

+


+


+

// moving bounds

+


+

(

+

~lo = PLseq((60..70));

+

~hi = PLseq((80..90));

+

)

+


+

x.stop;

+


+


+ + diff --git a/Help/PLbindef.html b/Help/PLbindef.html new file mode 100755 index 0000000..499093e --- /dev/null +++ b/Help/PLbindef.html @@ -0,0 +1,380 @@ + + + + + + + + + + + +

PLbindef wrapper for Pbindef which allows replacement in object prototyping style

+


+

Part of: miSCellaneous

+


+

Inherits from: Pbindef

+


+

PLbindef works like a normal Pbindef and, like the latter, uses Pdef's global bookkeeping, but replacement of key streams can be done in object prototyping style with a dedicated PLbindefEnvironment, which also holds player methods. This Environment is itself assigned to the PLbindef's name in an Environment of choice, by default the current Environment. Setting can thus be done in very condensed syntax, also in combination with EventShortcuts.

+


+

NOTE: PLbindefs are registered globally in the same Dictionary as Pdefs, Pbindefs and PLbindefPars. It's recommended to do cleanup with 'clear' after using PLbindef / PLbindefPar as in examples below. Otherwise unwanted or strange behaviour might be caused by leftover sources when playing a new PLbindef / PLbindefPar example with same key. With SC >= 3.7 occasional posts of the default parent event occur with Pbindef, so also with PLbindef. I didn't notice any different other behaviour though.

+


+


+

See also: PLx suite, PLbindefPar, PLbindefEnvironment, PLbindefParEnvironment, EventShortcuts, PLx and live coding with Strings

+


+


+

Creation / Class Methods

+


+

*new (...args)

+

+

Creates a new PLbindef object. First arg should be the key, followed by key/value pairs for the Pbindef. The last arg can be an optional environment which determines where the corresponding PLbindefEnvironment should be stored, by default this is the current Environment at instantiation time.

+


+

+

Instance Methods

+


+

clear

+

+

As with Pbindef: stop, but in addition remove name entry from refEnvir and clear sourceEnvir.

+

+

sourceEnvir

+

+

Getter for PLbindef's PLbindefEnvironment.

+

+

refEnvir

+

+

Getter for the Environment where PLbindef's PLbindefEnvironment is associated with PLbindef's key.

+

+


+


+

Examples

+


+

// synthdefs to play with

+


+

(

+

SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1|

+

    var sig = { WhiteNoise.ar } ! 2;

+

    sig = BPF.ar(sig, freq, rq) *

+

        EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

        (rq ** -1) * (250 / (freq ** 0.8));

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+

)

+


+


+


+

Ex.1) Setting key streams

+

+

// store PLbindef under key \x

+


+

(

+

PLbindef(\x,

+

\instrument, \sin_grain,

+

\dur, 0.2,

+

\midinote, Pwhite(60, 90)

+

)

+

)

+


+

// Environment has been made and assigned to the variable ~x in currentEnvironment, check

+


+

~x

+


+


+

// now the Environment can also be treated as a player

+


+

~x.play

+


+


+

// set params while playing

+


+

~x.att = Pwhite(0.01, 0.2)

+


+

~x.midinote = 75

+


+

~x.att = 0.01

+


+

~x.dur = 0.02

+


+

~x.midinote = Pbrown(60, 90, 1.5)

+


+


+

// pause

+


+

~x.stop

+


+

// resume

+


+

~x.play

+


+


+


+

// use method 'value' for parallel setting

+


+

~x.(\dur, 0.05, \midinote, Pwhite(70.0, 72))

+


+

~x.stop

+


+

// cleanup

+


+

~x.clear

+


+


+


+

Ex.2) PLbindef with EventShortcuts

+

+

// syntax can be more condensed with EventShortcuts, turn it on, post defaults

+


+

EventShortcuts.on

+


+

EventShortcuts.postCurrent

+


+


+

(

+

PLbindef(\u,

+

\i, \saw_grain,

+

\d, 0.2,

+

\m, Pwhite(60, 90)

+

)

+

)

+


+

~u.play

+


+

~u.d = 0.1

+


+


+

~u.m = Pn(Plazy { Pseries(rrand(50, 70), 1.5, 20) })

+


+

~u.m = ~u.m + [0, 4, 7]

+


+

~u.i = PLseq([\sin_grain, \saw_grain])

+


+


+

~u.a = Pn(Pseries(0.05, 0.01, 20))

+


+

~u.m = 70

+


+


+

// stop + cleanup in one

+


+

~u.clear

+


+


+


+

Ex.3) PLbindef with VarGui

+

+

// start with gui and define pitch sequence with sliders

+


+

(

+

p = PLbindef(\z,

+

\i, \saw_grain,

+

\d, 0.2,

+

\m, PLseq(\midi)

+

);

+


+

VarGui([\midi, [50, 90, \lin, 1, 60] ! 7], stream: p).gui;

+

)

+


+


+

~z.m = PLseq(\midi) + [0, 5, 8]

+


+

~z.m = ~z.m + PLseq([-1, 0, 1] * 12)

+


+

~z.clear

+


+


+

Ex.4) PLbindef with PbindFx

+

+

See also Ex.7c in PbindFx help

+


+

// boot server with extended resources

+


+

(

+

s.options.numPrivateAudioBusChannels = 1024;

+

s.options.memSize = 8192 * 16;

+

s.reboot;

+

)

+


+

(

+

SynthDef(\echo, { |out, in, maxEchoDelta = 0.2, echoDelta = 0.1,

+

    decayTime = 1, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = DelayL.ar(

+

        CombL.ar(inSig, maxEchoDelta, echoDelta, decayTime, amp),

+

        maxEchoDelta,

+

        maxEchoDelta - echoDelta

+

    );

+

    Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+

SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000,

+

    cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = RLPF.ar(

+

        inSig,

+

        LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi),

+

        rq,

+

        amp

+

    ).softclip;

+

    Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+

SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1|

+

    var sig = { WhiteNoise.ar } ! 2;

+

    sig = BPF.ar(sig, freq, rq) *

+

        EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

        (rq ** -1) * (250 / (freq ** 0.8));

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+

)

+


+

// prepare EventShortcuts for additional keys

+


+

(

+

EventShortcuts.addOnBase(\default, \fxs, (

+

dec: \decayTime,

+

cd: \cleanupDelay,

+

cf: \cutOffMoveFreq,

+

fxo: \fxOrder,

+

dta: \echoDelta

+

), true);

+


+

EventShortcuts.makeCurrent(\fxs);

+


+

EventShortcuts.on;

+

)

+


+


+

(

+

// source and fxs passed as PLbindefs

+


+

k = [\q, \echo, \wah];

+


+

PLbindef(\q,

+

\i, PLrand([\noise_grain, \saw_grain]),

+

\d, 0.25,

+

\m, PLseq([60, 60, 60, 62]),

+

\fxo, PLseq([0, 0, 1, 2]),

+

// echo introduces delay, so do delay if no echo

+

\lag, Pfunc { |e| e.fxo.asArray.includes(1).if { 0 }{ 0.2 } },

+

\a, 0.1,

+

\att, 0.01,

+

\rel, 0.1,

+


+

\cd, Pkey(\att)+ Pkey(\rel) + 0.001

+

);

+


+

PLbindef(\echo,

+

\fx, \echo,

+

\dta, 0.06,

+

\a, 0.5,

+

\dec, Pwhite(0.3, 1.8),

+

\cd, Pkey(\dec)

+

);

+


+

PLbindef(\wah,

+

\fx, \wah,

+

\cf, Pwhite(1, 3),

+

\a, 0.5,

+

\cd, 0.01

+

);

+


+


+

p = PbindFx(*k.collect(PLbindef(_))); // PbindFx(*(k.collect { |x| PLbindef(x) }));

+


+

q = p.play;

+

)

+


+


+


+

// manipulate midinotes

+


+

~q.m = ~q.m + PLseq([0, 12, -12])

+


+

~q.m = ~q.m + PLrand([0, [0, -4]])

+


+

~q.m = ~q.m + PLrand([0, [0, -7]])

+


+


+

// rhythm

+


+

~q.d = PLshufn([1, 1, 2, 1] / 8)

+


+


+

// echo param and fx order sequence

+


+

~echo.dta = Pwhite(0.03, 0.08)

+


+

~q.fxo = PLseq([0, 0, 1, 2, 1, [1, 2]])

+


+


+


+

~q.m = 48

+


+

// produce overtone series with echodelta

+


+

~echo.dta = 1 / 24.midicps / PLseq((1..16))

+


+


+

// this also works in chords ("fx expansion")

+

// source is processed twice per event

+


+

~echo.dta = 1 / [24, 26.7].midicps / PLseq((1..16))

+


+


+


+

// cleanup

+


+

q.stop

+


+

k.do { |i| PLbindef(i).clear }

+


+


+ + diff --git a/Help/PLbindefEnvironment.html b/Help/PLbindefEnvironment.html new file mode 100755 index 0000000..8425a84 --- /dev/null +++ b/Help/PLbindefEnvironment.html @@ -0,0 +1,92 @@ + + + + + + + + + + + +

PLbindefEnvironment Environment made by PLbindef to play and set its sources

+


+

Part of: miSCellaneous

+


+

Inherits from: Environment

+


+

Instances of this class are made as side effect of PLbindef creation, assigned to PLbindef's name in an Environment of choice (by default the current one) and used as player interface as well as for setting PLbindef's sources in condensed prototyping syntax. They are not thought to be created explicitely though. See PLbindef for examples.

+


+

See also: PLx suite, PLbindef, PLbindefPar, PLbindefParEnvironment

+


+


+

Creation / Class Methods

+


+

*new (n, proto, parent, know, name)

+

+

Creates a new PLbindefEnvironment object with arguments of IdentityDictionary. In contrast to the latter know defaults to true, which allows setting sources of the PLbindef in object prototyping style. name is used for the corresponding key of the PLbindef. Normally not to be used explicitely.

+

+

Instance Methods

+


+

put (key, obj)

+

+

Associates obj with Symbol key and updates PLbindef's source.

+

+

superPut (key, obj)

+

+

Associates obj with Symbol key, mimicing IdentityDictionary::put.

+

+

value (...args)

+

+

Expects key/value pairs and applies put.

+

+

name

+

+

Getter for PLbindef's name.

+

+

plbindef

+

+

Getter for the corrresponding PLbindef.

+

+

play (clock, protoEvent, quant, doReset)

+

+

Plays the corresponding PLbindef with passed arguments.

+


+

isPlaying

+

+

Indicates if the corresponding PLbindef is playing.

+


+

resume

+

+

Resumes the corresponding PLbindef.

+


+

reset

+

+

Resets the corresponding PLbindef.

+


+

stop

+

+

Stops the corresponding PLbindef.

+


+

clear

+

+

Clears the corresponding PLbindef.

+

+

+

+ + diff --git a/Help/PLbindefPar.html b/Help/PLbindefPar.html new file mode 100755 index 0000000..88f77d4 --- /dev/null +++ b/Help/PLbindefPar.html @@ -0,0 +1,511 @@ + + + + + + + + + + + +

PLbindefPar container for parallel PLbindefs which allows replacement in object prototyping style

+


+

Part of: miSCellaneous

+


+

Inherits from: Pdef

+


+


+

PLbindefPar employs a number of parallel PLbindefs, replacement of key streams can be done in object prototyping style with a dedicated PLbindefParEnvironment, which also holds player methods. This Environment is itself assigned to the PLbindefPar's name in an Environment of choice, by default the current Environment. Setting can thus be done in very condensed syntax, also in combination with EventShortcuts.

+


+

NOTE: PLbindefPars are registered globally in the same Dictionary as Pdefs, Pbindefs and PLbindefs. In addition for size = n PLbindefs of the same name with indices i = 0, ... n-1 appended are stored globally. It's recommended to do cleanup with 'clear' after using PLbindef / PLbindefPar as in examples below. Otherwise unwanted or strange behaviour might be caused by leftover sources when playing a new PLbindef / PLbindefPar example with same key. With SC >= 3.7 occasional posts of the default parent event occur with Pbindef, so also with PLbindefPar. I didn't notice any different other behaviour though.

+


+


+

See also: PLx suite, PLbindef, PLbindefEnvironment, PLbindefParEnvironment, EventShortcuts, PLx and live coding with Strings

+


+


+

Creation / Class Methods

+


+

*new (...args)

+

+

Creates a new PLbindefPar object. First arg should be the key, followed by the number of parallel PLbindefs and the key/value pairs. Values are assigned to single PLbindefs according to the convention of PLbindefParEnvironment::put, see there and examples below. The last arg can be an optional environment which determines where the corresponding PLbindefParEnvironment should be stored, by default this is the current Environment at instantiation time.

+


+

+

Instance Methods

+


+

clear

+

+

Stop parallel PLbindefs and remove name entry from refEnvir.

+

+

remove

+

+

Removes not only the PLbindefPar but also associated PLbindefs from global entry.

+

+

sourceEnvir

+

+

Getter for PLbindefPar's PLbindefParEnvironment.

+

+

refEnvir

+

+

Getter for the Environment where PLbindefPar's PLbindefParEnvironment is associated with PLbindefPar's key.

+

+

size

+

+

Getter for PLbindefPar's number of parallel PLbindefs.

+

+

+


+

Examples

+


+

// synthdefs to play with

+


+

(

+

SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1|

+

    var sig = { WhiteNoise.ar } ! 2;

+

    sig = BPF.ar(sig, freq, rq) *

+

        EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

        (rq ** -1) * (250 / (freq ** 0.8));

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

EventShortcuts.on;

+

)

+


+


+


+

Ex.1) Setting key streams

+

+


+

// use with EventShortcuts

+


+

EventShortcuts.on

+


+

(

+

PLbindefPar(\v, 3,

+

    \i, [\saw_grain, \sin_grain, \noise_grain],

+

    \d, 0.8,

+

    \m, [65, 70, 80],

+

    \rq, 0.002,

+

\a, 0.03,

+

    \att, Pwhite(0.05, 0.01)

+

)

+

)

+


+

~v.play

+


+

// set all streams

+


+

~v.d = 0.2

+


+


+

// set single streams

+


+

~v[0].d = 0.1

+


+

~v[2].d = 0.4

+


+


+

// parallel intervals and chords for single streams

+


+

~v[2].m = Pwhite(80, 90) + [0, 9]

+


+

~v[0].m = Pwhite(50, 65) + [0, 5]

+


+

~v[1].m = Pwhite(70, 75.5) + [0, 3, 7]

+


+


+


+

// differentiate setting with collection

+


+

~v.m = [50, Pwhite(90, 80), 96]

+


+


+

// reference to last sources

+


+

~v.m = ~v.m + 1

+


+

~v[2].m = ~v[2].m - Pwhite(0, 5)

+


+


+


+

// pause single streams

+


+

~v[1].isRest = true

+


+

~v[1].isRest = false

+


+


+

// shorter, pause with amplitude setting

+


+

~v[0].a = 0

+


+

~v[0].a = 0.05

+


+


+


+

// differentiate setting with collection produced by Function

+


+

~v.m = { |i| (i * 15) + PLseq((0..9)) + [55, 60] } ! 3

+


+


+

// set only some streams with an index list, passed as first arg to 'value'

+


+

~v.([0, 1], \d, 0.3)

+


+

~v.([1, 2], \d, 0.5)

+


+


+

// set all, they might be time-shifted

+


+

~v.d = 0.2

+


+


+

// hard sync with reset

+


+

~v.reset

+


+

~v.stop

+


+

~v.clear

+


+


+


+

Ex.2) More parallel streams, from granular to additive

+

+

// use EventShortcuts

+


+

EventShortcuts.on

+


+

(

+

PLbindefPar(\y, 12,

+

// wrapped indexing: collection is used for all 12 streams

+

\i, [\saw_grain, \sin_grain, \noise_grain],

+

\d, (1..12)/100,

+

\m, { rrand(60, 90) } ! 12,

+

\a, 0.02,

+

\rq, 0.002

+

)

+

)

+


+

~y.play

+


+

// evaluate more than once

+


+

~y.m = { rrand(60, 90) } ! 12

+


+


+

// refer to current midinotes

+


+

~y.m = ~y.m - 1

+


+


+

~y.d = [1, 2, 4] / 8

+


+

~y.d = ~y.d / 4

+


+

~y.stop

+


+

~y.clear

+


+


+


+

// replacement introducing additive structures

+


+

(

+

PLbindefPar(\add, 12,

+

\i, \sin_grain, 

+

\d, 1, 

+

\m, { Pn(Pseries(rrand(40, 60), Pwhite(1.0, 3), 20)) } ! 12, 

+

\att, 5,

+

\rel, 5,

+

\a, 0.005

+

).play

+

)

+


+

~add.f = { PLseq((1..16)) * (100 + Pwhite(0.0, 3)) } ! 12

+


+

~add.stop

+


+

~add.clear

+


+


+


+


+

Ex.3a) PLbindefPar with VarGui, same control params for parallel streams

+

+

// if different streams should read from one control

+

// it's best to refer via a dedicated key

+


+


+

// start with gui and define pitch sequence with sliders

+


+

(

+

EventShortcuts.on;

+


+

p = PLbindefPar(\w, 3,

+

\i, [\saw_grain, \sin_grain, \noise_grain],

+

\d, 0.25,

+

\n, PLseq(\midi),

+

\m, [70, 75, 80] + Pkey(\n),

+

\a, 0.05,

+

\rq, 0.005

+

);

+


+

VarGui([\midi, [0, 12, \lin, 1, 0] ! 7], stream: p.trace).gui

+

)

+


+

~w.d = [1, 2, 4] / 8

+


+


+

// see difference

+


+

~w.m = [70, 75, 80].collect(Pkey(\n) + _)  // ~w.m = [70, 75, 80].collect { |i| Pkey(\n) + i }

+


+


+

~w.m = [70, 75, 80] + Pkey(\n)

+


+


+

// three streams of chords, all refering to same sequence

+


+

~w.m = { |i| 70 + Pkey(\n) + [0, 7, 14] - (i * 12) } ! 3

+


+


+

// manipulate step source

+


+

~w.n = Pstutter(3, PLseq(\midi))

+


+

~w.n = ~w.n + PLseq([0, 0.5, 1])

+


+


+

~w.d = [1, 3, 4] / 8

+


+


+

// cleanup after stopping with gui

+


+

~w.clear

+


+


+

Ex.3b) PLbindefPar with VarGui, different control params for parallel streams

+

+

// three array controls

+


+

(

+

EventShortcuts.on;

+


+

p = PLbindefPar(\t, 3,

+

\i, [\saw_grain, \sin_grain, \noise_grain],

+

\d, 0.25,

+

\n, { |i| PLseq((\midi ++ i).asSymbol) } ! 3,

+

\m, [60, 75, 90].collect { |i| Pkey(\n) + i },

+

\a, 0.05,

+

\rq, 0.005

+

);

+


+

VarGui(

+

// three array var controls

+

({ |i| [(\midi ++ i).asSymbol, [0, 12, \lin, 1, 0] ! 7] } ! 3).flatten,

+

stream: p

+

).gui

+

)

+


+

~t.d = [1, 3, 2] / 8

+


+

~t.m = [[50, 55, 60], [76, 77, 78, 79], [86, 90, 94]].collect(Pkey(\n) + _)

+


+


+

~t.d = PLrand([1, 3, 2]) / 8

+


+


+

~t[2].a = 0

+


+

~t[0].a = 0

+


+


+

// cleanup after stopping with gui

+


+

~t.clear

+


+


+


+

Ex.4) PLbindefPar with PbindFx

+

+

See also Ex.7c in PbindFx help

+


+

// boot server with extended resources

+


+

(

+

s.options.numPrivateAudioBusChannels = 1024;

+

s.options.memSize = 8192 * 16;

+

s.reboot;

+


+

// fx synths

+


+

SynthDef(\echo, { |out, in, maxEchoDelta = 0.2, echoDelta = 0.1,

+

    decayTime = 1, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = DelayL.ar(

+

        CombL.ar(inSig, maxEchoDelta, echoDelta, decayTime, amp),

+

        maxEchoDelta,

+

        maxEchoDelta - echoDelta

+

    );

+

    Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+

SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000,

+

    cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = RLPF.ar(

+

        inSig,

+

        LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi),

+

        rq,

+

        amp

+

    ).softclip;

+

    Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+


+

// prepare EventShortcuts for additional keys

+


+

EventShortcuts.addOnBase(\default, \fxs, (

+

dec: \decayTime,

+

cd: \cleanupDelay,

+

cf: \cutOffMoveFreq,

+

fxo: \fxOrder,

+

dta: \echoDelta

+

), true);

+


+

EventShortcuts.makeCurrent(\fxs);

+


+

EventShortcuts.on;

+

)

+


+


+

(

+

// source and fxs passed as PLbindefs

+


+

k = [\r, \echo, \wah];

+


+

PLbindefPar(\r, 12,

+

\i, [\noise_grain, \saw_grain],

+

\d, 0.25,

+

\m, PLseq([60, 60, 60, 62]),

+

\fxo, PLseq([0, 0, 1, 2]),

+

// echo introduces delay, so do delay if no echo

+

\lag, Pfunc { |e| e.fxo.asArray.includes(1).if { 0 }{ 0.2 } },

+

\a, 0.03,

+

\att, 0.01,

+

\rel, 0.1,

+


+

\cd, Pkey(\att)+ Pkey(\rel) + 0.001

+

);

+


+

PLbindef(\echo,

+

\fx, \echo,

+

\dta, 0.06,

+

\a, 1,

+

\dec, Pwhite(0.3, 1.8),

+

\cd, Pkey(\dec)

+

);

+


+

PLbindef(\wah,

+

\fx, \wah,

+

\cf, Pwhite(1, 3),

+

\a, 1,

+

\cd, 0.01

+

);

+


+

// all are Pdefs too, globally stored, so we can collect like this

+


+

p = PbindFx(*k.collect(Pdef(_))); // PbindFx(*(k.collect { |x| Pdef(x) }));

+


+

q = p.play;

+

)

+


+


+

// differentiate rhythm

+


+

~r.d = (1..12) / 8

+


+


+

// manipulate midinotes

+


+

~r.m = ~r.m + PLseq([0, 12, -12])

+


+

~r.m = ~r.m + PLrand([0, [0, -4]])

+


+

~r.m = ~r.m + PLrand([0, [0, -7]])

+


+


+


+

// echo param and fx order sequence

+


+

~echo.dta = Pwhite(0.03, 0.08)

+


+

~r.fxo = PLseq([0, 0, 1, 2, 1, [1, 2]])

+


+


+

~r.m = (48, 50..70)

+


+

// produce overtone series with echodelta

+


+

~echo.dta = 1 / 24.midicps / PLseq((1..16))

+


+


+

// this also works in chords ("fx expansion")

+

// source is processed twice per event

+


+

~echo.dta = 1 / [24, 26.7].midicps / PLseq((1..32).mirror)

+


+


+


+

// cleanup

+


+

q.stop

+


+

k.do { |i| Pdef(i).clear }

+


+


+


+ + diff --git a/Help/PLbindefParEnvironment.html b/Help/PLbindefParEnvironment.html new file mode 100755 index 0000000..b5390a8 --- /dev/null +++ b/Help/PLbindefParEnvironment.html @@ -0,0 +1,58 @@ + + + + + + + + + + + +

PLbindefParEnvironment Environment made by PLbindefPar to play and set its sources

+


+

Part of: miSCellaneous

+


+

Inherits from: PLbindefEnvironment

+


+

Instances of this class are made as side effect of PLbindefPar creation, assigned to PLbindefPar's name in an Environment of choice (by default the current one) and used as player interface and to set PLbindefPar's sources in condensed syntax. They are not thought to be created explicitely though. A PLbindefParEnvironment stores the sources passed with keys as well as the "unfolded" sources of single PLbindef streams. This is done by assigning PLbindefEnvironments to every Integer index of the PLbindefPar and updating them additionally. See PLbindefPar for examples.

+


+

See also: PLx suite, PLbindefPar, PLbindef, PLbindefEnvironment

+


+

Creation / Class Methods

+


+

*new (n, proto, parent, know, name, num, plbindef)

+

+

Creates a new PLbindefParEnvironment object with arguments of IdentityDictionary. In contrast to the latter know defaults to true, which allows setting sources of the PLbindefPar in object prototyping style. name is used for the corresponding key of the PLbindefPar. num is the number of parallel patterns in the PLbindefPar.

+

plbindef is the corresponding PLbindefPar. Normally not be used explicitely.

+

+

Instance Methods

+


+

put (key, obj)

+

+

Associates obj with Symbol key and updates PLbindefPar's source as well as the stored PLbindefEnvironments depending on the class of obj. For a SequenceableCollection items are assigned in the PLbindefEnvironments of corresponding indices (method 'wrapAt' is used for handling cases of smaller collections). Other passed objects are assigned in all PLbindefEnvironments. 

+

+

value (...args)

+

+

Expects key/value pairs and applies put. Optionally the first arg can be an Integer or a collection of Integers, specifying the PLbindefs to be set.

+

+

num

+

+

Getter for PLbindefPar's size.

+

+ + diff --git a/Help/PLbrown.html b/Help/PLbrown.html new file mode 100755 index 0000000..37292f4 --- /dev/null +++ b/Help/PLbrown.html @@ -0,0 +1,119 @@ + + + + + + + + + + + +

PLbrown dynamic scope Pbrown variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pbrown

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pbrown, PLgbrown, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, step, length, envir)

+

+

Creates a new PLbrown object.

+

+

lo - Symbol or Pbrown lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Pbrown hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

step - Symbol or Pbrown step arg. Defaults to 0.125.

+

If a Symbol is passed, step can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pbrown length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLbrown(\lo, \hi, \step);

+


+


+

// prepare current Environment

+

// PLseq repeats arg defaults to inf

+


+

(

+

~lo = 55;

+

~hi = 80;

+

~step = Pstutter(10, PLseq([0.05, 3.5]));

+

)

+


+


+

// run

+


+

(

+

x = Pbind(

+

\midinote, Ptuple(p!2), 

+

\dur, 0.1

+

).play;

+

)

+


+

// replace

+


+

(

+

~lo = Pseq((50..90));

+

~hi = Pseq((50..90) + 15);

+

)

+


+


+


+ + diff --git a/Help/PLcauchy.html b/Help/PLcauchy.html new file mode 100755 index 0000000..e3391cf --- /dev/null +++ b/Help/PLcauchy.html @@ -0,0 +1,114 @@ + + + + + + + + + + + +

PLcauchy dynamic scope Pcauchy variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pcauchy

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pcauchy, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (mean, spread, length, envir)

+

+

Creates a new PLcauchy object.

+

+

mean - Symbol or Pcauchy mean arg. Defaults to 0.

+

If a Symbol is passed, mean can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

spread - Symbol or Pcauchy spread arg. Defaults to 1.

+

If a Symbol is passed, spread can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pcauchy length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments,

+

// Cauchy distribution is not bounded, so do clip !

+


+

(

+

p = Pbind(

+

\midinote, PLcauchy(\mean, \spread).clip(60, 90),

+

\dur, 0.1

+

);

+

)

+


+

// prepare current Environment

+


+

(

+

~mean = 75;

+

~spread = 0.1;

+

)

+


+


+

// run

+


+

x = p.play;

+


+


+

// move mean value and distribution

+

// PLseq defaults to repeats = inf

+


+

(

+

~mean = PLseq((80, 79.7..70));

+

~spread = PLseq([0, 0, 0, 1]);

+

)

+


+

x.stop;

+


+


+ + diff --git a/Help/PLexprand.html b/Help/PLexprand.html new file mode 100755 index 0000000..37dd118 --- /dev/null +++ b/Help/PLexprand.html @@ -0,0 +1,114 @@ + + + + + + + + + + + +

PLexprand dynamic scope Pexprand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pexprand

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pexprand, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, length, envir)

+

+

Creates a new PLexprand object.

+

+

lo - Symbol or Pexprand lo arg. Defaults to 0.0001.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Pexprand hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pexprand length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments,

+

// intervals grow together with base tone

+


+

(

+

q = PLexprand(\lo, \hi);

+


+

p = Pbind(

+

\midinote, 60 + q + PLtuple([0, q]),

+

\dur, 0.1

+

);

+

)

+


+


+

// prepare current Environment

+


+

(

+

~lo = 0.1;

+

~hi = 10;

+

)

+


+


+

// run

+


+

x = p.play;

+


+


+

// replace  

+


+

~hi = 20;

+


+

x.stop;

+


+


+ + diff --git a/Help/PLgauss.html b/Help/PLgauss.html new file mode 100755 index 0000000..2191620 --- /dev/null +++ b/Help/PLgauss.html @@ -0,0 +1,115 @@ + + + + + + + + + + + +

PLgauss dynamic scope Pgauss variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pgauss

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pgauss, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (mean, dev, length, envir)

+

+

Creates a new PLgauss object.

+

+

mean - Symbol or Pgauss mean arg. Defaults to 0.

+

If a Symbol is passed, mean can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

dev - Symbol or Pgauss dev arg. Defaults to 1.

+

If a Symbol is passed, dev can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pgauss length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments,

+

// Gauss distribution is not bounded, so do clip !

+


+

(

+

p = Pbind(

+

\midinote, PLgauss(\mean, \dev).clip(60, 90),

+

\dur, 0.1

+

);

+

)

+


+

// prepare current Environment

+


+

(

+

~mean = 75;

+

~dev = 0.3;

+

)

+


+


+

// run

+


+

x = p.play;

+


+


+

// move mean value and distribution

+

// PLseq defaults to repeats = inf

+


+

(

+

~mean = PLseq((80, 79.75..70.25));

+

~dev = Pstutter(8, PLseq([4, 0]));

+

)

+


+

x.stop;

+


+


+ + diff --git a/Help/PLgbrown.html b/Help/PLgbrown.html new file mode 100755 index 0000000..4b74030 --- /dev/null +++ b/Help/PLgbrown.html @@ -0,0 +1,126 @@ + + + + + + + + + + + +

PLgbrown dynamic scope Pgbrown variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pgbrown

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pgbrown, PLbrown, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, step, length, envir)

+

+

Creates a new PLgbrown object.

+

+

lo - Symbol or Pgbrown lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Pgbrown hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

step - Symbol or Pgbrown step arg. Defaults to 0.125.

+

If a Symbol is passed, step can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pgbrown length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\midinote, PLgbrown(\lo, \hi, \step) + [0, -7.4, -12.7], 

+

\dur, 0.1,

+

\amp, 0.05

+

);

+

)

+


+

// prepare Environments

+


+

(

+

e = (lo: 65, hi: 90, step: 0.01);

+

f = e.copy.put(\step, 0.05);

+

)

+


+


+

// run

+


+

(

+

e.use { x = p.play(quant: 0.2) };

+

f.use { y = p.play(quant: 0.2) };

+

)

+


+

// replace

+


+

(

+

e.lo = 65;

+

f.lo = 65;

+

e.hi = Pwhite(65, 67);

+

f.hi = Pwhite(65, 95);

+

f.step = 0.3

+

)

+


+

y.stop;

+


+

x.stop;

+


+


+ + diff --git a/Help/PLgeom.html b/Help/PLgeom.html new file mode 100755 index 0000000..38a3527 --- /dev/null +++ b/Help/PLgeom.html @@ -0,0 +1,115 @@ + + + + + + + + + + + +

PLgeom dynamic scope Pgeom variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pgeom

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pgeom, PLseries, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (start, grow, length, envir)

+

+

Creates a new PLgeom object.

+

+

start - Symbol or Pgeom start arg. Defaults to 0.

+

If a Symbol is passed, start can be assigned to an envir variable later on.

+

grow - Symbol or Pgeom grow arg. Defaults to 1.

+

If a Symbol is passed, grow can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pgeom length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\freq, Pn(PLgeom(\start, \grow, 50)) % 2000 + 400,

+

\dur, 0.1

+

);

+

)

+


+

// prepare current Environment

+


+

(

+

~start = 100;

+

~grow = 1.1;

+

)

+


+


+

// from ascending to random

+


+

x = p.play;

+


+


+

// replace

+


+

~grow = 0.99;

+


+

~grow = 1.4;

+


+


+

x.stop;

+


+


+


+


+ + diff --git a/Help/PLhprand.html b/Help/PLhprand.html new file mode 100755 index 0000000..974519e --- /dev/null +++ b/Help/PLhprand.html @@ -0,0 +1,118 @@ + + + + + + + + + + + +

PLhprand dynamic scope Phprand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Phprand

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Phprand, PLlprand, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, length, envir)

+

+

Creates a new PLhprand object.

+

+

lo - Symbol or Phprand lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Phprand hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Phprand length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

q = PLhprand(\lo, \hi);

+


+


+

// prepare current Environment

+

// PLseq repeats arg defaults to inf

+


+

(

+

~lo = 60;

+

~hi = PLseq((92..62));

+

)

+


+


+

// run

+


+

(

+

y = Pbind(

+

\midinote, Ptuple(q!5), 

+

\dur, 0.1,

+

\amp, 0.05

+

).play;

+

)

+


+


+

// replace, converging bounds

+


+

(

+

~lo = PLseq((40..70) ++ (70!5));

+

~hi = 70.5;

+

)

+


+

y.stop;

+


+

// compare this example with lo-weighted PLlprand

+


+ + diff --git a/Help/PLlprand.html b/Help/PLlprand.html new file mode 100755 index 0000000..db22d61 --- /dev/null +++ b/Help/PLlprand.html @@ -0,0 +1,118 @@ + + + + + + + + + + + +

PLlprand dynamic scope Plprand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Plprand

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Plprand, PLhprand, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, length, envir)

+

+

Creates a new PLlprand object.

+

+

lo - Symbol or Plprand lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Plprand hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Plprand length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLlprand(\lo, \hi);

+


+


+

// prepare current Environment

+

// PLseq repeats arg defaults to inf

+


+

(

+

~lo = 60;

+

~hi = PLseq((92..62));

+

)

+


+


+

// run

+


+

(

+

x = Pbind(

+

\midinote, Ptuple(p!5), 

+

\dur, 0.1,

+

\amp, 0.05

+

).play;

+

)

+


+


+

// replace, converging bounds

+


+

(

+

~lo = PLseq((40..70) ++ (70!5));

+

~hi = 70.5;

+

)

+


+

x.stop;

+


+


+

// compare this example with hi-weighted PLhprand

+ + diff --git a/Help/PLmeanrand.html b/Help/PLmeanrand.html new file mode 100755 index 0000000..0ce43f6 --- /dev/null +++ b/Help/PLmeanrand.html @@ -0,0 +1,117 @@ + + + + + + + + + + + +

PLmeanrand dynamic scope Pmeanrand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pmeanrand

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pmeanrand, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, length, envir)

+

+

Creates a new PLmeanrand object.

+

+

lo - Symbol or Pmeanrand lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Pmeanrand hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pmeanrand length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLmeanrand(\lo, \hi);

+


+


+

// prepare current Environment

+

// PLseq repeats arg defaults to inf

+


+

(

+

~lo = PLseq((60, 60.25..70));

+

~hi = PLseq((70, 69.75..60));

+

)

+


+


+

// run

+


+

(

+

x = Pbind(

+

\midinote, Ptuple([p, 65]), 

+

\amp, [0.1, 0.06], 

+

\dur, 0.1

+

).play;

+

)

+


+


+

// replace

+


+

(

+

~lo = 60.5;

+

~hi = 61;

+

)

+


+

x.stop;

+


+


+ + diff --git a/Help/PLn.html b/Help/PLn.html new file mode 100755 index 0000000..1f67be9 --- /dev/null +++ b/Help/PLn.html @@ -0,0 +1,254 @@ + + + + + + + + + + + +

PLn dynamic scope placeholder pattern whose streams will be finished before replacements 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pn

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite. In contrast to PL a replacement doesn't take effect immediately, but with the next embedding. This behaviour might be preferred with syncing.

+

NOTE: As sources are finished before next replacements are possible, infinite source streams, other than with other PLx patterns, inhibit further replacements at all. For the option of finishing substreams with PLx list patterns see their cutItems arg and the last example below.

+


+

See also: PL, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (item, repeats, envir)

+

+

Creates a new PLn object.

+

+

item - Symbol or other Object. 

+

If a Symbol is passed, item can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Ex. 1 Protection of periods

+

+

// compare PL and PLn, start with polling two items from each Stream

+

// Note that Pseq defaults to repeats = 1 and PL/PLn default to repeats = inf

+


+

(

+

~a = Pseq([1, 2, 3]);

+

x = PLn(\a).asStream;

+

y = PL(\a).asStream;

+


+

x.nextN(2);

+

y.nextN(2);

+

)

+


+


+

// replace proxy source 

+


+

~a = ~a * 100;

+


+


+

// Stream from PLn finishes before replacement

+


+

x.nextN(2)

+


+

// With PL substream is replaced immediately

+


+

y.nextN(2)

+


+


+


+

Ex. 2 Protection of periods for syncing

+


+

// playing two interval lines in parallel

+


+

(

+

~a = Pseq([4, 2, 0]) + [0, -5];

+

~b = Pseq([7, 5, 4]) + [0, 5];

+

+

p = Pbind(

+

\dur, Pseq([0.4, 0.2, 0.2], inf),

+

\note, PLn(\a)

+

);

+

+

q = Pbindf(p, \note, PLn(\b));

+


+

x = Ppar([p, q]).play;

+

)

+

+


+

// replace the lower event stream, new notes start after end of embedding Pseq

+

+

~a = Pseq([3, 2, 0]) + [0, -5];

+


+


+

// replace second line

+


+

~b = Pseq([7, 5, 4]) + [5, 12];

+


+


+

// source nil stops event stream after end of embedding Pseq

+


+

~a = nil;

+


+


+


+

Ex. 3 Protection of periods and subperiods with event streams

+


+

// define two Pbinds of same length, play first

+


+

(

+

x = Pbind(

+

\dur, Pseq([0.4, 0.2, 0.2]),

+

\note, Pseq([4, 2, 0]) 

+

);

+


+

y = Pbind(

+

\dur, 0.2,

+

\note, Pseq([7, 7, 5, 4]) 

+

);

+


+

~a = x;

+


+

PLn(\a).play;

+

)

+


+

// switch between them several times, periods are protected

+


+

~a = y;

+


+

~a = x;

+


+


+

// define a sequence of parts, we want to exchange parts later on

+


+

(

+

~trill_1 = Pbind(

+

\dur, 0.4/3,

+

\note, Pseq([7, 9, 7]) 

+

);

+


+

~trill_2 = Pbind(

+

\dur, 0.4/5,

+

\note, Pseq([7, 8, 7, 8, 7]) 

+

);

+


+

~fin = Pbind(

+

\dur, 0.2,

+

\note, Pseq([5, 4]) 

+

);

+


+

~b = [~trill_1, ~fin];

+

)

+


+

// replace with a PLseq

+

// note that source must have repeats = 1,

+

// in order to protect substreams with PLseq and change the behaviour later on

+

// we pass to cutItmes a Function that, for now, returns false

+


+

(

+

~cutItems = false;

+

~a = PLseq(\b, 1, cutItems: \cutItems);

+


+

~b[0] = ~trill_2;

+

)

+


+

// helper function to generate trill patterns

+


+

~trill = { |lo, hi, dur, reps| Pbind(\dur, dur / reps, \note, Pser([lo, hi], reps)) };

+


+


+

// replace with a long slow trill

+


+

~b[0] = ~trill_3 = ~trill.(7, 9, 0.9, 5);

+


+


+


+

// replace back while long trill, 

+

// due to the current value ~cutItems = false it will be completed and

+

// replacement takes effect in next loop

+

+

~b[0] = ~trill_2;

+


+

// replace back

+


+

~b[0] = ~trill_3;

+


+


+

// change replacing behaviour

+


+

~cutItems = true;

+


+


+

// now replacing while long trill will take immediate effect

+


+

~b[0] = ~trill_2;

+


+


+

// stop

+


+

~a = nil

+


+


+


+


+


+

+


+


+


+ + diff --git a/Help/PLnaryFunc.html b/Help/PLnaryFunc.html new file mode 100755 index 0000000..2381555 --- /dev/null +++ b/Help/PLnaryFunc.html @@ -0,0 +1,126 @@ + + + + + + + + + + + +

PLnaryFunc dynamic scope Pnaryop variant for Functions 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pnaryop

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also:, Pnaryop, PLnaryop, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (func, pat, arglist, envir)

+

+

Creates a new PLnaryFunc object.

+

+

func - Symbol or func arg. 

+

If a Symbol is passed, func can be assigned to an envir variable later on.

+

Can be dynamically replaced by a Pattern or Stream.

+

pat - Symbol or pattern arg. 

+

If a Symbol is passed, pattern can be assigned to an envir variable later on.

+

Can be dynamically replaced by a Pattern or Stream.

+

arglist - Symbols or arglist args. 

+

They are starting with input for the Function's second arg,

+

as items from pat will be passed to its first. 

+

If Symbols are passed, arglist args can be assigned to envir variables later on.

+

Can be dynamically replaced by Patterns or Streams.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\midinote, PLnaryFunc(\f, \src, [\dev]),

+

\dur, 0.1

+

);

+

)

+


+


+

// define Environment and play

+


+

(

+

e = (f: { |x,y| x + y }, src: PLseq([61, 62]), dev: Pbrown(-5, 5, 0.2) );

+


+

e.use { x = p.play };

+

)

+


+


+

// replace Function input Patterns

+


+

e.dev = PLseq((0, 0.5..7));

+


+

e.src = PLseq([61,64,65]);

+


+


+

// replace Function 

+


+

e.f = { |x,y| x - y };

+


+

e.f = { |x,y| y * 4 + x };

+


+


+

x.stop;

+


+


+

See also PLx suite Ex. 5b.

+


+


+


+ + diff --git a/Help/PLnaryop.html b/Help/PLnaryop.html new file mode 100755 index 0000000..9816280 --- /dev/null +++ b/Help/PLnaryop.html @@ -0,0 +1,119 @@ + + + + + + + + + + + +

PLnaryop dynamic scope Pnaryop variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pnaryop

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite. For replacing operators dynamically take PLnaryFunc with the operator wrapped into a Function.

+


+

See also:, Pnaryop, PLnaryFunc, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (operator, pat, arglist, envir)

+

+

Creates a new PLnaryop object.

+

+

operator - Symbol or Pnaryop operator arg. 

+

If a Symbol is passed, operator can be assigned to an envir variable later on.

+

pat - Symbol or Pnaryop pattern arg. 

+

If a Symbol is passed, pattern can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

arglist - Symbols or Pnaryop arglist arg. 

+

If Symbols are passed, arglist args can be assigned to envir variables later on.

+

Can be dynamically replaced by Patterns or Streams.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+


+


+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\midinote, PLnaryop('+', \src, [\dev]),

+

\dur, 0.1

+

);

+

)

+


+


+

// define Environment and play

+


+

(

+

e = (src: PLseq([61,62]), dev: Pbrown(-5, 5, 0.2) );

+


+

e.use { x = p.play };

+

)

+


+


+

// replace

+


+

e.dev = PLseq((0, 0.5..7));

+


+

e.dev = Pbrown(-5, 5, 0.2);

+


+

e.src = PLseq([61,64,65]);

+


+


+

x.stop;

+


+


+

See also PLx suite Ex. 5a.

+


+


+


+ + diff --git a/Help/PLpoisson.html b/Help/PLpoisson.html new file mode 100755 index 0000000..c66e87b --- /dev/null +++ b/Help/PLpoisson.html @@ -0,0 +1,107 @@ + + + + + + + + + + + +

PLpoisson dynamic scope Ppoisson variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Ppoisson

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Ppoisson, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (mean, length, envir)

+

+

Creates a new PLpoisson object.

+

+

mean - Symbol or Ppoisson mean arg. Defaults to 1.

+

If a Symbol is passed, mean can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Ppoisson length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments,

+

// Poisson distribution gives positive integer values

+


+

(

+

p = Pbind(

+

\midinote, (PLpoisson(\mean) + 50).clip(60, 90),

+

\dur, 0.1

+

);

+

)

+


+


+

// prepare current Environment

+


+

~mean = 10;

+


+


+

// run

+


+

x = p.play;

+


+


+

// changing mean value 

+


+

~mean = Pstutter(5, PLseq((0, 5..30)));

+


+

x.stop;

+


+


+ + diff --git a/Help/PLrand.html b/Help/PLrand.html new file mode 100755 index 0000000..3f2b47e --- /dev/null +++ b/Help/PLrand.html @@ -0,0 +1,177 @@ + + + + + + + + + + + +

PLrand dynamic scope Prand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Prand, PLxrand, PLwrand, PLshuf, PLshufn, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, cutItems, envir)

+

+

Creates a new PLrand object.

+

+

list - Symbol or Prand list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Prand repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// define Pattern and prepare Environments

+

+

(

+

p = Pbind(

+

\midinote, PLrand(\a),

+

\dur, 0.2

+

);

+


+

e = (a: (67..72));

+

f = (a: (77..82));

+

)

+


+

// start together or not, but sync anyway

+


+

e.use { x = p.play(quant: 0.2) };

+

f.use { y = p.play(quant: 0.2) };

+


+


+

// replace array elements ...

+


+

f.a[0] = 97;

+


+

e.a[0] = 96;

+


+


+

// ... or arrays 

+


+

f.a = (72, 72.5..77);

+


+

e.a = [60];

+


+

e.a = [Pseq([60, 47.5]) + [0, 5], [61, 65.5]];

+


+

x.stop;

+

y.stop;

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLrand(\a);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.2

+

)

+

];

+


+

x = p.play;

+

)

+


+


+

// replace array element

+


+

(

+

~a[0] = Pbind(

+

\midinote, Pwhite(70, 75, 3) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+


+

// replace whole array

+


+

(

+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.05

+

),

+

Pbind(

+

\midinote, Pwhite(70, 90, 2),

+

\dur, 0.25

+

)

+

];

+

)

+


+

x.stop;

+


+ + diff --git a/Help/PLseq.html b/Help/PLseq.html new file mode 100755 index 0000000..59c5ceb --- /dev/null +++ b/Help/PLseq.html @@ -0,0 +1,171 @@ + + + + + + + + + + + +

PLseq dynamic scope Pseq variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pseq, PLser, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, offset, cutItems, envir)

+

+

Creates a new PLseq object.

+

+

list - Symbol or Pseq list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Pseq repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

offset - Symbol or Pseq offset arg. Defaults to 0.

+

If a Symbol is passed, offset can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\midinote, PLseq(\a),

+

\dur, 0.1

+

);

+

)

+


+


+

// assign a value to variable ~a in current Environment,

+

// play there.

+

// PLseq defaults to repeats = inf, Pseq defaults to repeats = 1

+


+

(

+

~a = (67..70) ++ Pseq((99..70));

+


+

x = p.play;

+

)

+


+


+

// try replacing Pseq stream while chromatic line down,

+

// works immediately with default value cutItems = true

+


+

~a[4] = 73;

+


+


+

// replace whole list

+


+

~a = (60..65);

+


+

x.stop;

+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLseq(\a);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.2

+

)

+

];

+


+

x = p.play;

+

)

+


+


+

// replace array element

+


+

(

+

~a[0] = Pbind(

+

\midinote, Pwhite(70, 75, 3) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+

// replace whole array

+


+

(

+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.05

+

),

+

Pbind(

+

\midinote, Pwhite(70, 90, 2),

+

\dur, 0.25

+

)

+

];

+

)

+


+

x.stop;

+


+


+


+


+ + diff --git a/Help/PLser.html b/Help/PLser.html new file mode 100755 index 0000000..5162ab2 --- /dev/null +++ b/Help/PLser.html @@ -0,0 +1,144 @@ + + + + + + + + + + + +

PLser dynamic scope Pser variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PLseq

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pser, PLseq, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, offset, cutItems, envir)

+

+

Creates a new PLser object.

+

+

list - Symbol or Pser list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Pser repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

offset - Symbol or Pser offset arg. Defaults to 0.

+

If a Symbol is passed, offset can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

(

+

// PLseq not used as proxy, only taken as it defaults to repeats = inf

+


+

p = Pbind(

+

\midinote, PLseq([PLser(\a, \r), 60, 61]),

+

\dur, 0.2

+

);

+


+

// prepare current Environment

+


+

~a = (67..70);

+

~r = 6;

+

)

+


+

x = p.play;

+


+


+

// replace repeats

+


+

~r = 3;

+


+


+

// replace array elements

+


+

~a[0] = [77, 93.5];

+


+

~a[2] = Pseq((94..96));

+


+


+

// replace whole array

+


+

~a = [55, 52];

+


+

x.stop;

+


+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLser(\a, 3);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.1

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.1

+

)

+

];

+


+

x = p.play;

+

)

+


+ + diff --git a/Help/PLseries.html b/Help/PLseries.html new file mode 100755 index 0000000..c8d021c --- /dev/null +++ b/Help/PLseries.html @@ -0,0 +1,120 @@ + + + + + + + + + + + +

PLseries dynamic scope Pseries variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pseries

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pseries, PLgeom, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (start, step, length, envir)

+

+

Creates a new PLseries object.

+

+

start - Symbol or Pseries start arg. Defaults to 0.

+

If a Symbol is passed, start can be assigned to an envir variable later on.

+

step - Symbol or Pseries step arg. Defaults to 1.

+

If a Symbol is passed, step can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pseries length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

(

+

p = Pbind(

+

\midinote, PLseries(0, \step) % 24 + 60,

+

\dur, 0.1

+

);

+

)

+


+

// prepare Environments

+


+

(

+

e = (step: 1);

+

f = e.copy;

+

)

+


+


+

// run

+


+


+

e.use { x = p.play(quant: 0.1) };

+


+

f.use { y = p.play(quant: 0.1) };

+


+


+

// replace

+


+

f.step = 2;

+


+

e.step = Pwhite(0.5, 1.5);

+


+

f.step = Pwhite(1, -3);

+


+


+


+

y.stop;

+


+

x.stop;

+


+


+ + diff --git a/Help/PLshuf.html b/Help/PLshuf.html new file mode 100755 index 0000000..014878e --- /dev/null +++ b/Help/PLshuf.html @@ -0,0 +1,179 @@ + + + + + + + + + + + +

PLshuf dynamic scope Pshuf variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite. A PLshuf stream keeps a permutation until it ends or there is a list replacement. See PLshufn for ongoing choice of new permutations.

+


+

See also: Pshuf, Pshufn, PLshufn, PLrand, PLxrand, PLwrand, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, cutItems, envir)

+

+

Creates a new PLshuf object.

+

+

list - Symbol or Pshuf list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Pshuf repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

(

+

p = Pbind(

+

\midinote, PLshuf(\a),

+

\dur, 0.2

+

);

+


+

// prepare Environment

+


+

~a = (67..72);

+

)

+


+

x = p.play;

+


+


+

// replace array elements ...

+


+

~a[0] = 63;

+


+


+

// ... or whole arrays 

+

// evaluating more than once gives a newly chosen permutation  

+


+

~a = (60..65);

+


+

x.stop;

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLshuf(\a);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 6),

+

\dur, 0.1

+

)

+

];

+


+

x = p.play;

+

)

+


+


+

// replace array element

+


+

(

+

~a[2] = Pbind(

+

\midinote, Pwhite(70, 75, 3) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+


+

// replace whole array

+


+

(

+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3) + [0, 5],

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pwhite(70, 80, 2) + [0, 4],

+

\dur, 0.25

+

),

+

Pbind(

+

\midinote, Pwhite(95, 100, 6) + [0, -9],

+

\dur, 0.05

+

)

+

];

+

)

+


+

x.stop;

+


+


+


+


+ + diff --git a/Help/PLshufn.html b/Help/PLshufn.html new file mode 100755 index 0000000..cb7e365 --- /dev/null +++ b/Help/PLshufn.html @@ -0,0 +1,188 @@ + + + + + + + + + + + +

PLshufn dynamic scope Pshufn variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PLshuf

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite. A PLshufn stream keeps on choosing permutations for the current list. See PLshuf for keeping one permutation.

+


+


+

See also: Pshufn, Pshuf, PLshuf, PLrand, PLxrand, PLwrand, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, cutItems, envir)

+

+

Creates a new PLshufn object.

+

+

list - Symbol or Pshufn list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Pshufn repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+


+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

(

+

p = Pbind(

+

\midinote, PLshufn(\a),

+

\dur, 0.2

+

);

+


+

// prepare Environments

+


+

e = (a: (67..72));

+

f = (a: (77..82));

+

)

+


+

e.use { x = p.play(quant: 0.2) };

+

f.use { y = p.play(quant: 0.2) };

+


+


+

// replace array elements ...

+


+

e.a[0] = 97;

+

f.a[0] = 98;

+


+


+

// ... or arrays 

+


+

(

+

e.a = [80, 81];

+

f.a = (70..73);

+

)

+


+

e.a[0] = Pwhite(60, 65, 1) + [0, -5, 29.5];

+


+

y.stop;

+

x.stop;

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLshufn(\a);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 6),

+

\dur, 0.1

+

)

+

];

+


+

x = p.play;

+

)

+


+


+

// replace array element

+


+

(

+

~a[2] = Pbind(

+

\midinote, Pwhite(70, 75, 3) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+

// replace whole array

+


+

(

+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3) + [0, 5],

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pwhite(70, 80, 2) + [0, 4],

+

\dur, 0.25

+

),

+

Pbind(

+

\midinote, Pwhite(95, 100, 6) + [0, -9],

+

\dur, 0.05

+

)

+

];

+

)

+


+

x.stop;

+


+


+


+ + diff --git a/Help/PLslide.html b/Help/PLslide.html new file mode 100755 index 0000000..a7b32e2 --- /dev/null +++ b/Help/PLslide.html @@ -0,0 +1,194 @@ + + + + + + + + + + + +

PLslide dynamic scope Pslide variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pslide, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, len, step, start, wrapAtEnd, cutItems, envir)

+

+

Creates a new PLslide object.

+

+

list - Symbol or Pslide list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Pslide repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

len - Symbol or Pslide len arg. Defaults to 3.

+

If a Symbol is passed, len can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

step - Symbol or Pslide step arg. Defaults to 1.

+

If a Symbol is passed, step can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

start - Symbol or Pslide start arg. Defaults to 0.

+

If a Symbol is passed, start can be assigned to an envir variable later on.

+

wrapAtEnd - Symbol or Pslide wrapAtEnd arg. Defaults to true.

+

If a Symbol is passed, wrapAtEnd can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLslide(\a, inf, \len, \step, \start);

+


+


+

// prepare current Environment

+


+

(

+

~len = 3;

+

~step = 1;

+

~start = 0;

+

~a = [60, 61, 62, 70, 71, 72, 80, 81, 82];

+

)

+


+


+

// run

+


+

(

+

x = Pbind(

+

\midinote, p, 

+

\dur, 0.2

+

).play;

+

)

+


+


+

// replace list elements

+


+

~a[0] = 60.5;

+


+

~a[8] = Pseq([92, 80.5], 1);

+


+


+


+

// len and step can be replaced by Patterns

+

// PLseq defaults to repeats = inf

+


+

~len = Pstutter(5, PLseq([1, 2, 3]));

+


+

(

+

~len = 1;

+

~step = Pstutter(2, PLseq([0, 4]));

+

)

+


+

x.stop;

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLslide(\a, inf, \len, \step, \start);

+


+

~len = 3;

+

~step = 1;

+

~start = 0;

+

~add = 0;

+


+

~a = (60, 62..70).collect { |x|

+

Pbind(

+

\midinote, x + Pseq((0, 0.2..0.8)) + PL(\add),

+

\dur, 0.1

+

);

+

};

+


+

x = p.play;

+

)

+


+


+

// replace slide params an ~add

+


+

~add = [4, 9];

+


+

~step = 2;

+


+

~len = 4;

+


+

~add = [4, 9, 13];

+


+


+


+

// replace array element

+


+

(

+

~a[0] = Pbind(

+

\midinote, 80 + Pseq((0.8, 0.6..0)) + PL(\add),

+

\dur, 0.05

+

);

+

)

+


+

x.stop;

+


+


+


+


+


+ + diff --git a/Help/PLswitch.html b/Help/PLswitch.html new file mode 100755 index 0000000..48515de --- /dev/null +++ b/Help/PLswitch.html @@ -0,0 +1,192 @@ + + + + + + + + + + + +

PLswitch dynamic scope Pswitch variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_Pattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pswitch, PLswitch1, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, which, cutItems, envir)

+

+

Creates a new PLswitch object.

+

+

list - Symbol or Pswitch list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

which - Symbol or Pswitch which arg. Defaults to 0.

+

If a Symbol is passed, which can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLswitch(\a, \w);

+


+


+

// define array

+

// PLseq defaults to repeats = inf

+


+


+

(

+

~a = (70..75) ++ Pshuf((85..80), 2) ++ Pseq((90..94));

+


+

~w = PLseq((0..7));

+


+

x = Pbind(\midinote, p, \dur, 0.1).play;

+

)

+


+

// update array element

+


+

~a[2] = Pseq([86, 85], 2) + [0, 3];

+


+


+

// reverse index pattern

+


+

~w = PLseq((7..0));

+


+


+

// keep in mind that indices are wrapped, no surprise here ...

+


+

~a = (70,72..84);

+


+


+

// ... but with shorter array indices are grouped in 5 + 3

+


+

~a = (70,72..78);

+


+

x.stop;

+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLswitch(\a, \w);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(70, 75, 3),

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.1

+

),

+

Pbind(

+

\midinote, Pwhite(90, 95, 6),

+

\dur, 0.05

+

)

+

];

+


+

~w = PLseq((0..3));

+


+

x = p.play;

+

)

+


+


+

// replace index sequence

+


+

~w = PLseq([3, 0]);

+


+

~w = PLseq([1, 2]);

+


+


+

// replace array element

+


+

(

+

~a[2] = Pbind(

+

\midinote, Pwhite(70, 75, 3) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+


+

// replace whole array

+


+

(

+

~a = [ Pbind(

+

\midinote, Pwhite(60, 65, 3) + [0, 5],

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pwhite(70, 80, 2) + [0, 4],

+

\dur, 0.25

+

),

+

Pbind(

+

\midinote, Pwhite(95, 100, 6) + [0, -9],

+

\dur, 0.05

+

)

+

];

+

)

+


+

x.stop;

+


+


+ + diff --git a/Help/PLswitch1.html b/Help/PLswitch1.html new file mode 100755 index 0000000..1739334 --- /dev/null +++ b/Help/PLswitch1.html @@ -0,0 +1,197 @@ + + + + + + + + + + + +

PLswitch1 dynamic scope Pswitch1 variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PLswitch

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pswitch1, PLswitch, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, which, cutItems, envir)

+

+

Creates a new PLswitch1 object.

+

+

list - Symbol or Pswitch1 list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

which - Symbol or Pswitch1 which arg. Defaults to 0.

+

If a Symbol is passed, which can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLswitch1(\a, \w);

+


+


+

// run Pbind in current Environment

+

// take PLseq as they already default to repeats = inf

+


+

(

+

~a = [PLseq((85..80)), PLseq((65..70))];

+

~w = PLseq([0, 1]);

+


+

x = Pbind(\midinote, p, \dur, 0.1).play;

+

)

+


+

// update array element

+


+

~a[1] = PLseq([96, 95]);

+


+


+

// update array

+


+

~a = [59, 85];

+


+


+

// update index pattern, used to stop also 

+


+

~w = Pseq([0, 0, 1], 5);

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLswitch1(\a, \w);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(70, 75),

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85),

+

\dur, 0.1

+

),

+

Pbind(

+

\midinote, Pwhite(90, 95),

+

\dur, 0.05

+

)

+

];

+


+

~w = PLseq((0..3));

+


+

x = p.play;

+

)

+


+


+

// replace index sequence

+


+

~w = PLseq([3, 0]);

+


+

~w = PLseq([1, 2]);

+


+


+

// replace array element

+


+

(

+

~a[2] = Pbind(

+

\midinote, Pwhite(70, 75) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+


+

// replace whole array

+


+

(

+

~a = [ Pbind(

+

\midinote, Pwhite(60, 65) + [0, 5],

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pwhite(70, 80) + [0, 4],

+

\dur, 0.25

+

),

+

Pbind(

+

\midinote, Pwhite(95, 100) + [0, -9],

+

\dur, 0.05

+

),

+

Pbind(

+

\midinote, Pwhite(95, 100) + [0, -14],

+

\dur, 0.02

+

)

+

];

+

)

+


+

~w = PLshuf((0..3));

+


+

~w = PLshufn((0..3));

+


+


+

x.stop;

+


+


+ + diff --git a/Help/PLtuple.html b/Help/PLtuple.html new file mode 100755 index 0000000..06131ab --- /dev/null +++ b/Help/PLtuple.html @@ -0,0 +1,124 @@ + + + + + + + + + + + +

PLtuple dynamic scope Ptuple variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Ptuple, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, cutItems, envir)

+

+

Creates a new PLtuple object.

+

+

list - Symbol or Ptuple list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Ptuple repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLtuple(\a);

+


+


+

// prepare current Environment

+

// PLtuple defaults to repeats = inf,

+

// so inner Patterns are repeatedly embedded

+


+

~a = [ Pshuf((60..65)), 70, Pshuf((75..80)) ];

+


+


+

// run

+


+

x = Pbind(\midinote, p, \dur, 0.2).trace.play;

+


+


+

// replace elements

+


+

~a[0] = 72.5;

+


+

~a[1] = 74.5;

+


+

~a[2] = Prand([85, 86, 87]);

+


+


+

// replace array

+


+

// Ptuple and PLtuple start with new embedding of ALL patterns

+

// if one ends, so here default repeats = inf of PLshuf has no effect:

+

// new permutation with every loop as Pshuf has repeats = 1

+


+

~a = [ Pshuf((60..65)), 70, PLshuf((75..80)) ];

+


+


+

// both Patterns have repeats = inf,

+

// permutation is kept

+


+

~a = [ PLshuf((60..65)), 70, PLshuf((75..80)) ];

+


+


+

x.stop;

+


+ + diff --git a/Help/PLwalk.html b/Help/PLwalk.html new file mode 100755 index 0000000..5fda89d --- /dev/null +++ b/Help/PLwalk.html @@ -0,0 +1,222 @@ + + + + + + + + + + + +

PLwalk dynamic scope Pwalk variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pwalk, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, stepPattern, directionPattern, startPos, cutItems, envir)

+

+

Creates a new PLwalk object.

+

+

list - Symbol or Pwalk list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

stepPattern - Symbol or Pwalk stepPattern arg. Defaults to Prand([1, -1], inf).

+

If a Symbol is passed, stepPattern can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

directionPattern - Symbol or Pwalk directionPattern arg. Defaults to 1.

+

If a Symbol is passed, directionPattern can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

startPos - Symbol or Pwalk startPos arg. Defaults to 0.

+

If a Symbol is passed, startPos can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLwalk(\a, \step, \dir, \start);

+


+


+

// prepare current Environment

+


+

(

+

~a = (60, 64..102);

+

~step = 1;

+

~start = 70;

+

~dir = -1;

+

)

+


+


+

// run

+


+

(

+

x = Pbind(

+

\midinote, p + [0, 3], 

+

\dur, 0.1, 

+

\legato, 1.2

+

).play;

+

)

+


+


+

// replace with Patterns

+

// PLx ListPatterns default to repeats = inf

+


+

~step = PLrand([1, 2]);

+


+

~dir = PLseq([-1, 1]);

+


+


+

// replace list

+


+

~a = ~a - 1.5;

+


+


+

x.stop;

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+


+

(

+

p = PLwalk(\a, \step, \dir);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 1) + [0, -8.7],

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(70, 75, 2) + [0, -3.3],

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 90, 3) + [0, -4.3],

+

\dur, 0.1

+

),

+

Pbind(

+

\midinote, Pwhite(90, 100, 2) + [0, 5.7],

+

\dur, 0.05

+

)

+

];

+


+

~step = 1;

+


+

~dir = 1;

+


+

x = p.play;

+

)

+


+


+

// replace step pattern, pending between two source patterns

+

// try evaluating several times

+


+

~step = PLseq([1, -1]);

+


+

~step = 1;

+


+


+

// replace array element

+


+

(

+

~step = 1;

+


+

~a[0] = Pbind(

+

\midinote, Pwhite(60, 75, 1) + [0, 5, 14, 19, 22],

+

\dur, 0.15

+

);

+


+

~a[3] = Pbind(

+

\midinote, Pseq((90..95)),

+

\dur, 0.05

+

);

+

)

+


+


+

// replace whole array

+


+

(

+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.05

+

),

+

Pbind(

+

\midinote, Pwhite(70, 90, 2),

+

\dur, 0.25

+

),

+

Pbind(

+

\midinote, Pwhite(70, 75, 3),

+

\dur, 0.05

+

),

+

Pbind(

+

\midinote, Pwhite(80, 95, 3) + [0, -5.3],

+

\dur, 0.3

+

)

+

];

+

)

+


+

x.stop;

+


+


+


+


+


+


+ + diff --git a/Help/PLwhite.html b/Help/PLwhite.html new file mode 100755 index 0000000..0314b10 --- /dev/null +++ b/Help/PLwhite.html @@ -0,0 +1,113 @@ + + + + + + + + + + + +

PLwhite dynamic scope Pwhite variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pwhite

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pwhite, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (lo, hi, length, envir)

+

+

Creates a new PLwhite object.

+

+

lo - Symbol or Pwhite lo arg. Defaults to 0.

+

If a Symbol is passed, lo can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

hi - Symbol or Pwhite hi arg. Defaults to 1.

+

If a Symbol is passed, hi can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

length - Symbol or Pwhite length arg. Defaults to inf.

+

If a Symbol is passed, length can be assigned to an envir variable later on.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// definition for future reference in arbitrary Environments

+


+

p = PLwhite(\lo, \hi);

+


+


+

// prepare current Environment

+

// PLseq repeats defaults to inf

+


+

(

+

~lo = PLseq((60..70));

+

~hi = PLseq((62..72));

+

)

+


+


+

// run

+


+

(

+

x = Pbind(

+

\midinote, p, 

+

\dur, 0.1 

+

).play;

+

)

+


+


+

// replace, converging bounds, stops when ~lo ends (Pseq default repeats = 1)

+


+

(

+

~lo = Pseq((60..80) ++ (80!5));

+

~hi = 80;

+

)

+


+


+


+


+ + diff --git a/Help/PLwrand.html b/Help/PLwrand.html new file mode 100755 index 0000000..64236c6 --- /dev/null +++ b/Help/PLwrand.html @@ -0,0 +1,131 @@ + + + + + + + + + + + +

PLwrand dynamic scope Pwrand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pwrand, PLrand, PLxrand, PLshuf, PLshufn, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, weights, repeats, cutItems, envir)

+

+

Creates a new PLwrand object.

+

+

list - Symbol or Pwrand list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

weights - Symbol or Pwrand weights arg. 

+

If a Symbol is passed, weights can be assigned to an envir variable later on.

+

Can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Pwrand repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

(

+

p = Pbind(

+

\freq, 50 * PLwrand(\a, \w),

+

\dur, 0.01,

+

\amp, 0.02

+

);

+


+

// prepare (current) Environment

+

// give low overtones more weight

+


+

~a = (1..8); 

+

~w = (8..1).cubed.normalizeSum; 

+

)

+


+

x = p.play;

+


+


+

// reverse overtone weights

+


+

~w = (1..8).cubed.normalizeSum; 

+


+


+

// replace with Pattern for weights,

+

// PLseq taken as repeats defaults to inf

+


+

~w = Pstutter(50, PLseq([(8..1), (1..8)].collect { |x| x.cubed.normalizeSum }));

+


+


+

// replace arrays (must be sufficiently long)

+


+

~a = (3..10);

+

~a = (5..12);

+


+

~a = (1,3..15);

+

~a = (1,4..22);

+

~a = (1,5..29);

+

~a = (1,6..36);

+

~a = (2,7..37);

+

~a = (3,8..38);

+

~a = (4,9..39);

+

~a = (5,10..40);

+


+

x.stop;

+


+


+ + diff --git a/Help/PLx and live coding with Strings.html b/Help/PLx and live coding with Strings.html new file mode 100644 index 0000000..1d113cd --- /dev/null +++ b/Help/PLx and live coding with Strings.html @@ -0,0 +1,778 @@ + + + + + + + + + + + +

PLx and live coding with Strings PLx patterns as placeholders for sequencing with letters

+


+

Part of: miSCellaneous

+


+

See also: PLx suite, PsymNilSafe, PLbindef, PLbindefPar, EventShortcuts

+


+


+

Strings and Chars as high-level representations for musical objects can be used for sequencing with very condensed syntax. This is already possible with standard patterns like Pseq etc. – PLx list patterns fit this concept as their referenced Arrays/Strings can be replaced on the fly. Examples below also use EventShortcuts to minimize typing.

+


+

WARNING: Sequencing with infinite Patterns/Streams has always the potential of hangs. E.g. Psym hangs if all referenced pattern return nil (SC 3.7.2). Here convenience method 'symplay' is suggested: it employs PsymNilSafe, its method 'embedInStream' performs a check like in James Harkins' PnNilSafe from ddwPatterns quark (which can't be used directly this case). 'symplay' thus avoids hangs of that type, see Ex. 2b.

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

(

+

// synthdefs to play with, use of EventShortcuts

+


+

SynthDef(\noise, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1|

+

    var sig = { WhiteNoise.ar } ! 2;

+

    sig = BPF.ar(sig, freq, rq) *

+

        EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

        (rq ** -1) * (250 / (freq ** 0.8));

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\sin, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+


+

SynthDef(\saw, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

EventShortcuts.on;

+

)

+


+


+

Ex.1) Straight usage with finite Patterns and Events

+


+

(

+

// use EventShortcuts

+


+

EventShortcuts.on;

+

EventShortcuts.postAll;

+


+

// base Pbind

+


+

~x = Pbind(\d, 0.1, \i, \sin);

+


+

// chars for the string, event patterns or events

+


+

~a = Pbind(\m, Pseries(60, 2, 4)) <> ~x;

+

~b = Pbind(\m, Pseries(80, -2, 8)) <> ~x;

+

~c = (i: \saw, m: [95, 96, 97], d: 0.8);

+


+

// define sequence

+


+

~p = "aab"

+

)

+


+

// symplay wraps into a PsymNilSafe

+

// PLseq defaults to repeats = inf and refers to 'p' in current Environment,

+

// thus the String "aab", the EventStreamPlayer should also get a name for start/stop,

+

// in this case we take the same letter (p) as interpreter variable

+


+

p = PLseq(\p).symplay

+


+


+

// replace String of PLseq

+


+

~p = "aacb"

+


+


+

// use of basic String operations

+


+

~p = ~p ++ "cc"

+


+

~p = ~p.reverse

+


+


+

(

+

// new char and sequence

+


+

~d = Pbind(\m, Pwhite(60, 90, 2), \i, \noise) <> ~x;

+

~p = "adadcb";

+

)

+


+

// replace String

+


+

~p = "bbcbcad"

+


+


+

// new chars

+

// the Function as first arg of Pseries is evaluated with every embedding,

+

// thus movements up and down start on different pitches

+


+

(

+

~a = Pbind(\m, Pseries({ rrand(60, 75) }, 7, 4)) <> ~x;

+

~b = Pbind(\m, Pseries({ rrand(85, 95) }, -5, 8)) <> ~x;

+

~c = Pbind(\i, \noise, \m, Pn((95..100), 2)) <> ~x

+

)

+


+


+

// modify ~b

+


+

~b = Pbind(\i, PLrand([\sin, \saw])) <> ~b;

+


+


+

// modify list, loop goes on

+

// evaluate several times, compare sound and posted String

+


+

~p = ~p.scramble

+


+

p.stop

+


+


+


+

Ex.2) Repeated embedding

+


+

// Control of embedding resp. the number of Events, that one Patterns should produce when played,

+

// is a subtle topic. A basic distinction is whether an embedded sequence should be produced with 

+

// desired behaviour from begin to end (2a) or it should be paused and resumed (2b). 

+

// The latter is the classical behaviour of Streams, but it can be mimiced with PSx stream patterns. 

+

// In any case embedding can be done with varying length, e.g. by defined sequences or by interaction.

+


+


+

Ex.2a) Embedding without continuation

+


+

(

+

// base Pbinds

+

~x = Pbind(\d, 0.15, \i, \sin, \rel, 1.5, \a, 0.02);

+

~y = Pbind(\d, Pn(0.9, 1), \i, \saw, \att, 0.8, \rel, 4, \a, 0.006);

+


+

// variable for repeats arg

+

~ar = 4;

+


+

// descending sequence, note the repeats arg: as with the start arg

+

// the Function is evaluated with every embedding,

+

// ~ar can be a Stream or a value

+

~a = Pbind(\m, Pseries({ rrand(75.0, 95) }, -7, { ~ar.next })) <> ~x;

+


+

// chords without octave doubling

+

~b = Pbind(\m, Pfunc { { [48, 60, 72].choose } ! 9 + (0..12).scramble.drop(3) }) <> ~y;

+


+

// define sequence

+

~p = "ba"

+

)

+


+


+

p = PLseq(\p).symplay

+


+

// change to other repeats number

+


+

~ar = 6

+


+

// make it a sequence with a Stream

+


+

~ar = PLseq([2, 2, 4]).asStream  // or shorter: PLseq([2, 2, 4]).iter

+


+


+

// go back to num and change String

+


+

~ar = 3

+


+

~p = "baaa"

+


+

~p = "baabaaaa"

+


+


+

p.stop

+


+


+


+

Ex.2b) Embedding with continuation

+


+

// This can be done by feeding a stream into a pattern, either directly or with PSx

+


+

(

+

// base Pbind

+

~x = Pbind(\d, 0.2, \rel, 0.5, \a, 0.03);

+


+

// Streams to be continued

+


+

~as = (Pbind(\m, Pn(Pseries(60, 1, 16)), \i, \saw) <> ~x).asStream;

+

~bs = (Pbind(\m, Pn(Pseries(90, -1, 16)), \i, \sin) <> ~x).asStream;

+


+

// variable for repeats args

+

~ar = 4;

+

~br = 4;

+


+

// for getting next values of an event stream we must pass an empty event as arg '.next(())'

+

~a = Pfuncn({ ~as.next(()) }, { ~ar.next });

+

~b = Pfuncn({ ~bs.next(()) }, { ~br.next });

+


+

// define sequence

+

~p = "ab"

+

)

+


+


+

p = PLseq(\p).symplay

+


+


+

// change repeats

+


+

~ar = 2;

+

~br = 1;

+


+


+

// this causes ~a to produce nils, only ~b still returns events

+


+

~ar = nil;

+


+

// This stops the player.

+

// Note that this kind of nil-detection works because 'symplay' employs PsymNilSafe.

+

// A construct like Psym(Pseq("ab", inf), ...).play would hang in that case

+


+

~br = nil;

+


+

// Note that this is different from the case, when the dictionary's key itself is nil.

+

// Then we get silent events, that also would't cause a hang with Psym(Pseq("ab", inf), ...).play

+


+


+

// evaluate above code starting from ~x = ... again and run

+


+

p = PLseq(\p).trace.symplay

+


+

// now we get a rest event

+


+

~a = nil

+


+

// player keeps running silently, stop explicitely

+


+

~b = nil

+


+

p.stop

+


+


+

// same as above written with PSx stream patterns

+


+

(

+

// base Pbind

+

~x = Pbind(\d, 0.2, \rel, 0.5, \a, 0.03);

+


+

// variable for repeats args

+

~ar = 4;

+

~br = 4;

+


+

~a = PS(Pbind(\m, Pn(Pseries(60, 1, 16)), \i, \saw) <> ~x, { ~ar.next });

+

~b = PS(Pbind(\m, Pn(Pseries(90, -1, 16)), \i, \sin) <> ~x, { ~br.next });

+


+

// define sequence

+

~p = "ab"

+

)

+


+


+

p = PLseq(\p).symplay

+


+

// change repeats

+


+

~ar = 2;

+

~br = 1;

+


+

p.stop;

+


+


+

Ex.3) Parallel embedding

+


+

// This can e.g. be done with Ppar, Ptuple or Pspawner, which is most flexible.

+

// There's a tiny isssue here in combination with EventShortcuts, duration keys

+

// should be in full length (You could apply method 'eventShortcuts' inside Ppar,

+

// but that's even more typing in that case, so we just write 'dur' instead of 'd').

+


+

(

+

// base Pbind

+


+

~x = Pbind(\dur, 0.1, \i, \sin);

+

~y = Pbind(\dur, 0.05, \i, \sin);

+


+

// chars for the String, event patterns or events

+


+

~a = Pbind(\m, Pseries({ rrand(60.0, 65) }, 1, 8)) <> ~x;

+

~b = Pbind(\m, Pseries({ rrand(85.0, 95) }, -1, 8)) <> ~y;

+


+

~c = Ppar([~a, ~b]);

+


+

~d = (i: \saw, m: [95, 96, 97], d: 0.8);

+


+

// define sequence

+


+

~p = "accd"

+

)

+


+


+

p = PLseq(\p).symplay

+


+

// equivalent with Pspawner

+


+

~c = Pspawner { |sp| sp.par(~a); sp.par(~b) };

+


+


+

// with Pspawner you have precise control over embedding of subsequences

+


+

~c = Pspawner { |sp| sp.par(~a); 4.do { sp.par(~b) } };

+


+


+

~e = Pspawner { |sp| sp.par(~a); 3.do { sp.seq(~b) } };

+


+

~p = "acde"

+


+

p.stop

+


+


+


+

Ex.4) Use of other PLx list patterns

+


+

// We can keep the String constant and switch to different PLx list patterns.

+


+

(

+

// base Pbind

+


+

~x = Pbind(\d, 0.1, \i, \saw);

+

~y = Pbind(\d, 0.2, \i, \sin);

+


+

// chars for the String, event patterns or events

+


+

~a = Pbind(\m, Pseries(60, Pwhite(1.0, 7.0), 4)) <> ~x;

+

~b = Pbind(\m, Pseries(80, Pwhite(1.0, 7.0), 4)) <> ~y;

+


+

~c = ~x <> ~b;

+

~d = ~y <> ~a;

+


+

~e = Pbind(\i, \noise, \m, Pn(70, 2)) <> ~x;

+


+

// define sequence

+


+

~p = "abcde"

+

)

+


+


+

// we need another proxy in that case, take general PL

+


+

~l = PLseq(\p);

+


+

p = PL(\l).symplay;

+


+


+

// scramble sequence and keep

+


+

~l = PLshuf(\p);

+


+


+

// scramble with every loop

+


+

~l = PLshufn(\p);

+


+


+


+

// weighted random

+


+

~l = PLwrand(\p, [4, 1, 3, 1, 1]/10);

+


+

p.stop;

+


+


+


+

Ex.5) PLbindef and PLbindefPar

+


+

// High-level control of Strings can be combined with replacing key streams with PLbindef/PLbindefPar

+


+


+

Ex.5a) PLbindef

+


+

(

+

// base PLbindef, continued embedding with PS as in Ex. 2b

+


+

~x = PS(PLbindef(\y, \dur, 0.1, \i, \noise, \rq, 0.5, \att, 0.05, \rel, 0.1, \a, 0.05));

+


+

// chars for the String, event patterns or events

+


+

~a = Pbind(\m, Pn(75, 1)) <> ~x;

+

~b = Pbind(\m, Pn(80, 1)) <> ~x;

+


+

~c = Ppar([~a, ~b]);

+


+

// define sequence

+


+

~p = "ab"

+

)

+


+

p = PLseq(\p).symplay

+


+


+

// update PLbindef's rq and amplitude with patterns

+


+

~y.rq = PLseq((100..1).mirror / 1000)

+


+

~y.a = PLseq((20..80).mirror / 1000)

+


+


+

// update String

+


+

~p = "c"

+


+

~p = "ababccc"

+


+


+

// stop and cleanup

+


+

p.stop

+


+

PLbindef(\y).remove

+


+


+


+

Ex.5b) PLbindefPar

+


+

(

+

// data base for two PLbindefPars, continued embedding with PS as in Ex. 2b

+


+

~w = [\dur, 0.1, \i, \noise, \rq, 0.5, \att, 0.05, \rel, 0.1, \a, 0.02];

+


+

~chord = (46, 53..95);

+


+

~a = PS(PLbindefPar(\u, 7, \m, ~chord, *~w), 1);

+

~b = PS(PLbindefPar(\v, 7, \m, ~chord + 2, *~w), 1);

+


+

// define sequence

+


+

~p = "ab"

+

)

+


+

p = PLseq(\p).symplay

+


+


+

~u.rq = 0.005

+


+

~v.i = \saw

+


+


+

// evolving changes

+


+

~u.rq = PLseq((100, 95..5).mirror / 1000)

+


+

~v.a = Pseg(PLseq([0.01, 0.04]), Pwhite(4, 7))

+


+


+

// change sequence per String

+


+

~p = "aabb"

+


+

~p = "aabbabab"

+


+

~p = "aabbcababc"

+


+

~p = "aaaab"

+


+


+

// fade out

+


+

~v.a = Pseg(Pseq([0.02, 0]), 20)

+


+

~u.a = Pseg(Pseq([0.02, 0]), 20)

+


+


+

// stop and cleanup

+


+

(

+

p.stop;

+

PLbindef(\u).remove;

+

PLbindef(\v).remove;

+

)

+


+


+


+

Ex.6) String sequencing with PbindFx

+


+

// Control with Strings can be thought in many ways.

+

// With effects one can e.g. use different Strings for src and fx sequencing.

+


+


+

Ex.6a) PbindFx

+


+

// boot server with extended resources for PbindFx

+


+

(

+

s.options.numPrivateAudioBusChannels = 1024;

+

s.options.memSize = 8192 * 16;

+

s.reboot;

+


+

// fx synths

+


+

SynthDef(\resample, { |out = 0, in, mix = 1, amp = 1,

+

resampleRate = 22050, lagTime = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = Latch.ar(inSig, Impulse.ar(resampleRate)); // resampling

+

// lag in milliseconds for smoothing

+

sig = sig.lag(lagTime * 0.001);

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+

SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000,

+

    cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+

    sig = RLPF.ar(

+

        inSig,

+

        LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi),

+

        rq,

+

        amp

+

    ).softclip;

+

    Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+


+

// src synths

+


+

SynthDef(\noise, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1|

+

    var sig = { WhiteNoise.ar } ! 2;

+

    sig = BPF.ar(sig, freq, rq) *

+

        EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

        (rq ** -1) * (250 / (freq ** 0.8));

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\saw, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

    var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2;

+

    sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

    OffsetOut.ar(out, sig);

+

}).add;

+


+


+

// prepare EventShortcuts for additional keys

+


+

EventShortcuts.addOnBase(\default, \fxExs, (

+

dec: \decayTime,

+

cd: \cleanupDelay,

+

cf: \cutOffMoveFreq,

+

fxo: \fxOrder,

+

rs: \resampleRate

+

), true);

+


+

EventShortcuts.makeCurrent(\fxExs);

+


+

EventShortcuts.on;

+

)

+


+


+


+

(

+

// base Pbind

+

// PbindFx's fxOrder (short: fxo) syntax employed by Symbol mapping:

+

// u: no fx, x: resample, y: wah, z: resample and wah in sequence

+


+

~r = Pbind(

+

\fxo, Psym(PLseq(\fx), (u:0, x:1, y:2, z:[1, 2])),

+

\a, 0.07,

+

\att, 0.01,

+

\rel, 0.3,

+

    \cd, Pkey(\att)+ Pkey(\rel) + 0.1

+

);

+


+

// PS to embed

+


+

~a = PS(Pbind(\i, \saw, \d, 0.1, \m, PLseq([60, 60, 60, 62])) <> ~r, 1);

+


+

~b = PS(Pbind(

+

\i, \noise,

+

\d, 0.2,

+

\m, PLseq([Pwhite(41.0, 50),Pwhite(71.0, 80)]),

+

\rq, 0.01

+

) <> ~r, 1);

+


+

// no cleanupDelay defaults for fxs as they don't delay

+

q = PbindFx(PsymNilSafe(PLseq(\p)), [

+

    \fx, \resample,

+

\mix, 0.3,

+

\rs, Pwhite(200, 500),

+

\a, 1

+

],[

+

   \fx, \wah,

+

\mix, 0.8,

+

\cf, Pwhite(0.5, 5),

+

\a, 0.7

+

]);

+

)

+


+

// start instrument sequence with no fx

+


+

(

+

~fx = "u";

+

~p = "aab";

+

p = q.play;

+

)

+


+

// fx sequences

+


+

~fx = "uuxy"

+


+

~fx = "uyuxzzzz"

+


+


+

~p = "b"

+


+

p.stop

+


+


+


+

Ex.6b) PbindFx and PLbindef

+


+

// There's more fine-tuned control if we can replace key streams also

+


+

(

+

// base pairs for PLbindef

+


+

~r = [

+

\fxo, Psym(PLseq(\fx), (u:0, x:1, y:2, z:[1, 2])),

+

\a, 0.07,

+

\att, 0.01,

+

\rel, 0.3,

+

    \cd, Pkey(\att) + Pkey(\rel) + 0.001

+

];

+


+

// PS to embed

+


+

~a = PS(PLbindef(\aa, \i, \saw, \d, 0.1, \m, PLseq([60, 60, 60, 62]), *~r), 1);

+


+

~b = PS(PLbindef(\bb,

+

\i, \noise,

+

\d, 0.2,

+

\m, PLseq([Pwhite(41.0, 50),Pwhite(71.0, 80)]),

+

\rq, 0.1,

+

*~r

+

), 1);

+


+

// as we have defined fx chars 'x' and 'y' above,

+

// choose related names 'xx' and'yy' for PLbindefs

+


+

q = PbindFx(PsymNilSafe(PLseq(\p)),

+

PLbindef(\xx,

+

    \fx, \resample,

+

\mix, 0.3,

+

\rs, Pwhite(200, 500),

+

\a, 1

+

),

+

PLbindef(\yy,

+

   \fx, \wah,

+

\mix, 0.8,

+

\cf, Pwhite(0.5, 5),

+

\a, 0.7

+

)

+

);

+

)

+


+

// start with no fxs

+


+

(

+

~fx = "u";

+

~p = "aab";

+

p = q.play;

+

)

+


+

// fx sequence

+


+

~fx = "uuxy"

+


+


+

// midinote for ~a and ~b

+


+

~aa.m = [50, 52]

+


+

~bb.m = Pwhite(80, 96)

+


+


+


+

// switch to single fx resample for testing changes of its control streams

+

// resample, test rate

+


+

~fx = "x"

+


+

~xx.rs = Pwhite(1000, 3000)

+


+


+

// same with wah

+


+

~fx = "y"

+


+

~yy.cf = 3

+


+


+

// src changes

+


+

~aa.rel = 0.1

+


+

~bb.rel = 0.5

+


+


+

// further playing

+


+

~fx = "xxy"

+


+

~p = "aabaabaaaabb"

+


+


+

~aa.m = [38, 40]

+


+

~bb.rq = 0.7

+


+

~fx = "z"

+


+


+

// fade out

+


+

~aa.a = Pseg(Pseq([0.04, 0]), 20)

+


+

~bb.a = Pseg(Pseq([0.04, 0]), 20)

+


+


+

// cleanup

+


+

p.stop

+


+

Pdef.removeAll

+


+


+


+


+


+


+


+


+


+ + diff --git a/Help/PLx suite.html b/Help/PLx suite.html new file mode 100755 index 0000000..a4d8eb5 --- /dev/null +++ b/Help/PLx suite.html @@ -0,0 +1,606 @@ + + + + + + + + + + + +

PLx, a dynamic scope Pattern suite dynamic scope Pattern variants 

+


+

Part of: miSCellaneous

+


+

See also: Event patterns and Functions, PLx and live coding with Strings, VarGui, VarGui shortcut builds, Buffer Granulation, Live Granulation

+


+


+

Environmental variables within functions can act as placeholders for values, but also Patterns itself. So Patterns including functional code (e.g. Pfunc, Plazy, Pcollect) can, thanks to dynamic scoping, turn into different Streams, depending on the environment where streamifying happens (Event patterns and Functions). This can be used for getting a whole parametrized family of Streams / EventStreamPlayers from a single pattern definition. Other applications are on-the-fly replacements and gui control of parameters of Pbinds / EventStreamPlayers with VarGui. Nevertheless constructs with Plazy, Pfunc etc. require some redundant typing which is saved by PLx Patterns (lazy evaluation). They are either plain wrapper classes or include variant implementations for the most common pattern types and deliver a more or less unified way for the described kind of placeholding.

+

Unification however can only be approximated as Patterns, even those of one type (e.g. ListPatterns), are defining different behaviour: not all inputs of a source pattern x can be dynamically updated (e.g. the start of a Pseries), not all of them are allowed to be Patterns itself. Implementation and usage may differ a bit from class to class. If there is no PLx implementation of a source Pattern class you can use PL as a general pattern placeholder input, see PL help file for an example. PLbindef and PLbindefPar allow key stream replacements in shortcut object prototyping syntax.

+

NOTE: PLx patterns follow a paradigm of immediate replacement. There are cases though where you might prefer to finish streams or substreams before replacement, especially when syncing comes into play, for these options consider PLn and the cutItems arg of PLx list patterns.

+

A word of caution: feeding a looped process with an invalid input has always the potential to lead to hangs. See PsymNilSafe and PLx and live coding with Strings for some remarks on that.

+


+


+


+

PLx value and event pattern classes

+


+

PL, PLn, PLseq, PLser, PLrand, PLxrand, PLwrand, PLshuf, PLshufn, PLslide, PLtuple, PLwalk, PLswitch, PLswitch1

+


+


+

PLx value pattern classes

+


+

PLwhite, PLlprand, PLhprand, PLmeanrand, PLbrown, PLgbrown, PLseries, PLgeom, PLbeta, PLcauchy, PLgauss, PLpoisson, PLexprand

+


+


+

PLx filter pattern classes

+


+

PLnaryop, PLnaryFunc, PLIdev

+


+


+

PLx subclasses of Pdef

+


+

PLbindef, PLbindefPar

+


+


+


+


+

Example 1a: ListPatterns placeholder constructs with Plazy

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// This is how dynamic scope placeholding of a ListPattern 

+

// could be done with Plazy,

+

// Pn defaults to repeats = inf.

+


+

(

+

p = Pn(Plazy { Pseq(~a, 1) }); 

+


+

~a = (60..70);

+


+

x = Pbind(

+

\midinote, p,

+

\dur, 0.2

+

).play;

+

)

+


+


+

// First drawback: replacing of a new list doesn't have an immediate effect

+

// as the old list is looped through before.

+


+

// Try evaluating this before the end of the original loop.

+


+

~a = (75..84) ++ Pseq([85,86], 10);

+


+


+

// Second drawback: replacing of a single pattern element, 

+

// which corresponds to a stream just being embedded,

+

// doesn't have an immediate effect

+

// as this embedding is finished before.

+


+

// Try evaluating this during the trill, it doesn't have an 

+

// effect before the next loop.

+


+

~a[10] = 91;

+


+

x.stop;

+


+


+

Similar placeholder constructs with Pcollect and Pfunc have similar drawbacks concerning replacement. However, this type of "delayed replacement" might be wanted in some cases and is also possible with PLx patterns, see PLn and the cutItems arg of PLx list patterns.

+


+


+


+

Example 1b: PLx implementation of ListPatterns

+


+


+

PLx Patterns take symbols as input. Derived Streams get the values of the Environment of streamification.

+


+

(

+

p = Pbind(

+

\midinote, PLseq(\a),

+

\dur, 0.2

+

);

+


+

~a = (60..70);

+


+

y = p.play;

+

)

+


+


+

// replacement of the whole list has an immediate effect now,

+

// with Pseq the loop starts with the new list

+


+

~a = (75..84) ++ Pseq([85,86], 10);

+


+


+

// replacing a single element also has an immediate effect 

+

// (as PLseq's cutItems arg defaults to true),

+

// try evaluating during the trill

+


+

~a[10] = 91;

+


+

y.stop;

+


+


+

// PLx ListPattern implementations can also act as 

+

// ordinary ListPatterns if args are not Symbols. 

+

// Difference: repeats arg defaults to inf, 

+

// so you save typing in this case,

+

// but don't apply .all to Streams derived from such Patterns !

+


+

(

+

x = Pbind(

+

\midinote, PLseq((60..70)),

+

\dur, 0.2

+

).play;

+

)

+


+

x.stop;

+


+


+


+

Example 1c: PLx implementation of Non-ListPatterns 

+


+


+

// an explicit definition with Plazy

+


+

p = Pwhite(Pn(Plazy { ~lo }), Pn(Plazy { ~hi }), { ~r });

+


+


+

// similarily done implicitely by PLwhite

+


+

q = PLwhite(\lo, \hi, \r); 

+


+


+

// streamify in envir

+


+

e = (lo: 60, hi: 90, r: 30);

+


+

e.use { q.asStream.all };

+


+


+

// reset repeats to inf and streamify again

+


+

e.use { ~r = inf; x = Pbind(\midinote, q, \dur, 0.2).play };

+


+


+

// replace lower bound by pattern

+


+

e.lo = PLseq([60, 90]);

+


+

x.stop;

+


+


+


+

Example 1d: Plain PL

+


+

A general placeholder that can be updated after instantiation.

+

Its repeats arg defaults to inf.

+


+


+

PL(\a, \r);

+


+

// roughly equivalent to

+


+

Pn(Plazy { ~a }, { ~r });

+


+


+

e = (a: Pseq((60, 62.5..80)));

+


+

e.use { x = Pbind(\midinote, PL(\a), \dur, 0.1).play }

+


+


+

// note that with this replacement new scrambles are chosen 

+

// repeatedly because Pshuf's repeats arg defaults to 1.

+


+

e.a = Pshuf((80, 78.5..65));

+


+


+

// fixed reordering

+


+

e.a = Pshuf((80, 78.5..65), inf);

+


+

e.a = PLshuf((80, 78.5..65));

+


+


+

x.stop;

+


+


+

PL can also be used with Patterns which don't have a PLx implementation.

+

See PL for an example.

+


+


+


+

Example 2: Playing in different Environments 

+


+


+

// Pbind to be streamified differently in different environments

+


+

(

+

p = Pbind(

+

\midinote, PLseq(\a),

+

\dur, PL(\d)

+

);

+


+

e = (a: (67..72), d: 0.1);

+

f = (a: (85..90), d: 0.2);

+

)

+


+


+

// start in sync or individually

+


+

x = e.use { p.play(quant: 0.2) };

+

y = f.use { p.play(quant: 0.2) };

+


+


+

// replacement of array elements ...

+


+

e.a[0] = 95;

+

f.a[0] = [75, 79];

+


+


+

// ... which may also be Patterns

+


+

f.a[0] = Pseq([75, 79], 3);

+


+


+

// replacing the whole array

+


+

f.a = (83..80);

+


+

f.a = (79..75) +.t [0, 3.5];

+


+

e.a = [Pseq([63, 65.5], 4), 85, 87];

+


+

x.stop;

+

y.stop;

+


+


+


+

Example 3: Use with VarGui 

+


+

// basic form of a step sequencer (amp defaults to 0 in associated global ControlSpec)

+


+

(

+

\default.pVarGui(

+

ctrBefore: [\a, [0, 6, \lin, 1, 3] ! 8],

+

pBefore: [\degree, PLseq(\a) ]

+

).gui;

+

)

+


+

See VarGui and VarGui shortcut builds for further examples.

+


+


+


+

Example 4: The repeats arg

+


+


+

PLx Patterns' repeats arg defaults to inf. This makes sense in situations where you want to go on replacing items on the fly. If a PLx Patterns is itself enclosed you may want to set it to a different value. Anyway the resulting number of repeats is the product of outer and inner repeats.

+


+


+


+

// PL(\a) defaults to repeats = inf

+

// Pshuf defaults to repeats = 1, is embedded repeatedly and 

+

// so it continues producing new permutations (like Pshufn)

+


+

(

+

p = Pbind(

+

\midinote, PL(\a),

+

\dur, 0.15

+

);

+


+

~a = Pshuf((60..63));

+

)

+


+


+

x = p.play;

+


+


+

// same effect, but this is normal Pshufn behaviour

+


+

~a = Pshufn((60..63));

+

~a = Pshufn((60..63), inf);

+


+

x.stop;

+


+


+

// PL(\a, 2) demands inner repeats = inf for endless running

+


+

(

+

p = Pbind(

+

\midinote, PL(\a, 2),

+

\dur, 0.15

+

);

+


+

~a = Pshuf((60..63), inf);  

+

)

+


+

// now normal Pshuf behaviour

+


+

x = p.play;

+


+


+

// same achieved with PLshuf((60..63)) as it defaults to repeats = inf

+


+

~a = PLshuf((60..63));

+


+


+

// stop with a Pseq which defaults to repeats = 1, played twice because of PL(\a, 2)

+


+

~a = Pseq((70..65));

+


+


+


+

Example 5a: Updating input of N-ary operators

+


+

One may want to have the choice to update inputs of N-ary operators applied to Patterns too. A common case is clipping. Say you have a Pcauchy pattern (distribution with a relatively high number of outliers) and want to dynamically change its mean value and clip bounds.

+


+


+

// PLcauchy allows updating mean and spread arg (also with patterns)

+

// the collect function will read from envir variables with every new event

+


+

(

+

p = Pbind(

+

\midinote, PLcauchy(\m, \s).collect(_.clip(~lo, ~hi)),

+

\dur, 0.1

+

);

+

)

+


+

// define the environment

+


+

e = (m: 75, s: 1, lo: 60, hi: 90);

+


+

e.use { x = p.play };

+


+

// update upper bound to mean value

+


+

e.hi = 75;

+


+

x.stop;

+


+


+

// above pitch pattern could be written explicitely too with Pnaryop 

+


+

Pnaryop(\clip, PLcauchy(\m, \s), [Pfunc { ~lo }, Pfunc { ~hi }])

+


+

// more powerful: PL allows updating with patterns

+


+

Pnaryop(\clip, PLcauchy(\m, \s), [PL(\lo), PL(\hi)])

+


+

// even shorter: the PLnaryop class expands to the above

+


+

PLnaryop(\clip, PLcauchy(\m, \s), [\lo, \hi])

+


+


+

// In the simple case of updating clip bounds with values 

+

// maybe one would rather use the version with collect.

+


+

// But with Pnaryop you can pass a list of arbitrary patterns as arglist

+

// and with PLnaryop you can dynamically update with arbitrary patterns -

+

// both can be used for more differentiated control of clip bounds

+

// (or args of any other N-ary operator or Function).

+

// Also the source pattern can be replaced.

+


+

(

+

p = Pbind(

+

\midinote, PLnaryop(\clip, \pat, [\lo, \hi]),

+

\dur, 0.1

+

);

+

)

+


+

// define the environment and play

+


+

e = (pat: PLcauchy(\m, \s), m: 75, s: 1, lo: 60, hi: 90);

+


+

e.use { x = p.play };

+


+


+

// compare distributions

+


+

e.pat = PLgauss(\m, \s);

+


+


+

// switch back to Cauchy with more outliers

+


+

e.pat = PLcauchy(\m, \s);

+


+


+

// update bounds, lo bound 85 is mostly gone below, 

+

// so nearly every second event has this midinote

+

// vice versa with hi bound 65

+


+

e.lo = PLseq([60, 85]);

+


+

e.use { ~lo = 60; ~hi = PLseq([65, 90]) };

+


+


+

// clipping to a window that loops through the distribution:

+

// values are taking more or less the wandering clip bounds if lo or hi, 

+

// but are rather randomly distributed between clip bounds around the mean value

+


+

e.use { ~lo = PLseq((50..95)); ~hi = ~lo + 10 };

+


+

x.stop;

+


+


+

For replacing operators dynamically take PLnaryFunc with the operator wrapped into a Function.

+


+


+


+

Example 5b: Updating input of N-ary Functions

+


+

Self-defined functions can be used as with PLnaryop.

+


+


+

(

+

p = Pbind(

+

\midinote, PLnaryFunc(\f, \src, [\b, \c]),

+

\dur, 0.1

+

);

+

)

+


+

// define Environment

+


+

(

+

e = ();

+


+

e.src = Pstutter(3, PLseq((60, 70..90)));

+

e.b = PLseq((0..2));

+

e.c = 0;

+


+

e.f = { |x,y,z| x + y + z };

+

)

+


+


+

// run

+


+

e.use { x = p.play };

+


+


+

// replace function input

+


+

e.b = PLseq((0..1));

+


+

e.c = [-5, 0];

+


+

e.c = PLseq([[-5, 0], [0, 3]]);

+


+

e.b = PLshuf((0..3));

+


+


+

// replace function

+


+

e.f = { |x,y,z| x + (y * 1.2) + z };

+


+

e.f = { |x,y,z| x + y + (z * 1.7) };

+


+


+

x.stop;

+


+


+


+

Example 6: PLbind / PLbindef

+


+


+

// start PLbindef, an special Environment of that name is created for setting

+


+

p = PLbindef(\a, \midinote, 70).play

+


+

// set in it

+


+

~a.midinote = Pwhite(60, 80)

+


+

~a.midinote = ~a.midinote + [0, 4]

+


+

~a.dur = 0.25

+


+

// cleanup

+


+

(

+

p.stop;

+

p.remove;

+

)

+


+


+

// PLbindef sprouts parallel processes

+

// start 4 in unisono

+


+

p = PLbindefPar(\b, 4, \midinote, 60, \dur, 2, \amp, 0.03).play

+


+

// set single streams

+


+

~b[3].midinote = Pwhite(70, 70.5)

+


+

~b[3].dur = 0.05

+


+


+

~b[2].midinote = Pwhite(65.0, 67)

+


+

~b[2].dur = 0.1

+


+


+

// use method value for setting

+


+

~b.([0, 1], \midinote, Pwhite(50, 60), \dur, 0.1)

+


+


+

// general setting, now we probably aren't in sync

+


+

~b.dur = 2

+


+


+

// reset syncs

+


+

p.reset

+


+


+

// stop and cleanup

+


+

(

+

p.stop;

+

p.remove;

+

)

+


+


+


+ + diff --git a/Help/PLxrand.html b/Help/PLxrand.html new file mode 100755 index 0000000..55eff9c --- /dev/null +++ b/Help/PLxrand.html @@ -0,0 +1,187 @@ + + + + + + + + + + + +

PLxrand dynamic scope Pxrand variant 

+


+

Part of: miSCellaneous

+


+

Inherits from: PL_ListPattern

+


+

Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See PLx suite.

+


+

See also: Pxrand, PLrand, PLwrand, PLshuf, PLshufn, Event patterns and Functions, VarGui, VarGui shortcut builds

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, cutItems, envir)

+

+

Creates a new PLxrand object.

+

+

list - Symbol or Pxrand list arg. 

+

If a Symbol is passed, list can be assigned to an envir variable later on.

+

This lists's elements can be dynamically replaced by Patterns or Streams.

+

repeats - Symbol or Prand repeats arg. Defaults to inf.

+

If a Symbol is passed, repeats can be assigned to an envir variable later on.

+

cutItems - Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer.

+

If a Symbol is passed, cutItems can be assigned to an envir variable later on.

+

Determines if list items, which are Patterns or Streams themselves,

+

will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. 

+

The latter is the default behaviour (default value true).

+

For protecting whole lists from immediate replacements see PLn.

+

envir - Dictionary or one of the Symbols

+

\top, \t (topEnvironment), \current, \c (currentEnvironment).

+

Dictionary to be taken for variable reference. Defaults to \current.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// define Pattern and prepare Environments

+

+

(

+

p = Pbind(

+

\midinote, PLxrand(\a),

+

\dur, 0.2

+

);

+


+

e = (a: (67..72));

+

f = (a: (73..78));

+

)

+


+

// start together or not, but sync anyway

+


+

e.use { x = p.play(quant: 0.2) };

+

f.use { y = p.play(quant: 0.2) };

+


+


+

// replace array elements ...

+


+

f.a[0] = Pseq((0, 0.5..3) + 75);

+


+

e.a[0] = Pseq(60 - (0, 0.5..3));

+


+


+

// ... or arrays 

+


+

f.a = (72, 72.5..77);

+


+

e.a = [60];

+


+

e.a = [Pseq([60, 47.5]) + [0, 5], [61, 65.5], [80, 83.5]];

+


+

x.stop;

+

y.stop;

+


+


+


+

//////////////////////

+


+


+

// placeholder may also get lists of event patterns

+


+

(

+

p = PLxrand(\a);

+


+

~a = [ 

+

Pbind(

+

\midinote, Pwhite(60, 65, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(70, 75, 3),

+

\dur, 0.2

+

),

+

Pbind(

+

\midinote, Pwhite(80, 85, 3),

+

\dur, 0.2

+

)

+

];

+


+

x = p.play;

+

)

+


+


+

// replace array element

+


+

(

+

~a[0] = Pbind(

+

\midinote, Pwhite(70, 75, 3) + [0, 5],

+

\dur, 0.15

+

);

+

)

+


+


+

// replace whole array

+


+

(

+

~a = [ 

+

Pbind(

+

\midinote, Pxrand((60..65), 3),

+

\dur, 0.15

+

),

+

Pbind(

+

\midinote, Pxrand((85..95), 3),

+

\dur, 0.05

+

),

+

Pbind(

+

\midinote, Pxrand((70..80), 2),

+

\dur, 0.25

+

)

+

];

+

)

+


+

x.stop;

+


+ + diff --git a/Help/PS.html b/Help/PS.html new file mode 100755 index 0000000..f0121a3 --- /dev/null +++ b/Help/PS.html @@ -0,0 +1,291 @@ + + + + + + + + + + + +

PS (PStream, Pstream) Pattern that behaves like a Stream 

+


+

Part of: miSCellaneous

+


+

Inherits from: Plazy

+


+

See also: MemoRoutine, PSx stream patterns, PSdup, PSrecur, PSloop

+


+


+

In general Patterns are stateless. But e.g. for counted embedding in other Patterns the exception of stream-like behaviour is practical. PS might also be used in cases where Streams must not be passed to certain Patterns.

+


+

NOTE: Name and implementation of former Pstream has changed with miSCellaneous_v0.9, in compliance with other PSx patterns it's been renamed to PS / PStream, however for backwards compatibility Pstream will still work by subclassing.

+


+


+

Creation / Class Methods

+


+

*new (srcPat, length, bufSize, copyItems, copySets)

+

+

Creates a new PS object.

+

+

srcPat - Source pattern, might also be event pattern.

+

length - Number of output items, may be pattern or stream, defaults to inf.

+

bufSize - Size of buffer to store last values, defaults to 1.

+

copyItems - Determines if and how to copy items, which are which are either non-Sets or member of Sets. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). 

+

Other values are interpreted as 0. Defaults to 0.

+

0: original item 

+

1: copy item

+

2: deepCopy item

+

copySets - Determines if to copy Sets (and hence Events). 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). 

+

Other values are interpreted as 0. Defaults to 1.

+

0: original Set 

+

1: copy Set

+

+

NOTE 1: The distinction of copying items and sets makes sense in the case of event streams.

+

Per default Events are copied (copySets == 1), not their values (copyItems == 0). 

+

By playing Events those are used to store additional data (synth ids, msgFuncs …) 

+

which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use 

+

MemoRoutine - copied Events will not contain this additional data. 

+

If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured 

+

then copying makes no sense, this is the normal case, so copyItems defaults to 0.

+

When going to alter the ouput, you might want to set copyItems to 1 for a PSx returning 

+

simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set

+

copySets to 1 and copyItems to 2 (an option copySets == 2 doesn't exist as

+

it would be contradictory in combination with copyItems < 2).

+


+

NOTE 2: Copy options concern copying into PS's buffer as well as 

+

the output of a Stream derived from the PS. When such a Stream is outputting copies 

+

this prevents unintended altering of items from srcPat. On the other hand

+

storing copies in PS's buffer prevents these from being altered unintendedly.

+


+


+

Instance Methods

+


+

lastValue

+

+

Last value stored in memoRoutine

+


+

lastValues

+

+

Array of last values stored in memoRoutine, latest value is first in array.

+

+

at (i)

+

+

Returns ith item of array of last values stored in memoRoutine

+

(keep in mind reversed order: last value first)

+

+

bufSize

+

+

Size of array of last values.

+


+

bufSeq(dropNils)

+

+

Returns items of the array lastValues, but in the order in which they appeared, i.e. 

+

latest value is first in array. If dropNils is true (default), nils will be rejected from the array.

+


+

srcPat, srcPat_(value)

+

+

Instance variable getter and setter methods. 

+


+

length, length_(value)

+

+

Instance variable getter and setter methods. 

+


+

lengthStream, lengthStream_(value)

+

+

Instance variable getter and setter methods. 

+

+

memoRoutine, memoRoutine_(value)

+

+

Instance variable getter and setter methods. 

+


+

count, count_(value)

+

+

Instance variable getter and setter methods.

+

Counts each call of next / value / resume / run on the memoRoutine. 

+

If several Streams are derived from one PS each call of next on a derived Stream

+

will be counted by the memoRoutine and thus by the PS.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

// PS used to store a sequence of 6 events

+


+

(

+

p = Pbind(

+

\midinote, Pwhite(60, 90, 6),

+

\dur, Prand([0.2, 0.4], inf)

+

);

+


+

// As the sequence ends with nil, nil is also stored in the buffer of PStream's MemoRoutine.

+

// Hence to store the whole sequence we must increase the buffer size by 1.

+


+

q = PS(p, bufSize: 7);

+


+

q.play;

+

)

+


+


+

// values are shifted, so latest are first

+


+

q.lastValues

+


+


+

// method bufSeq gives items in order in which they appeared, dropping nils by default

+


+

q.bufSeq

+


+


+

// repeat original sequence

+


+

Pseq(q.bufSeq).play

+


+


+

// play in reverse order, as Stream has been finished there's also a nil to be dropped

+


+

Pseq(q.lastValues.drop(1)).play

+


+


+

+

// counted embedding of value patterns

+

// PLx variants default to repeats = inf

+


+

(

+

p = PLseq([ 

+

PS(PLseq((60..65)), 3), 

+

PS(PLseq((80..90)), Pwhite(2,5)) 

+

]); 

+


+

x = Pbind(

+

\midinote, p,

+

\dur, 0.1

+

).play;

+

)

+


+

x.stop;

+


+


+

// counted embedding of event patterns

+


+

(

+

p = Pbind(

+

\midinote, PLseq((55..70)) + Pfunc { [0, [4,5].choose] },

+

\dur, 0.2

+

);

+


+

q = Pbind(

+

\midinote, PLseq((80..100)),

+

\dur, 0.05

+

);

+


+

x = PLseq([

+

PS(p, Pwhite(2,6)), 

+

PS(q, Pwhite(2,6)) 

+

]).play;

+

)

+


+

x.stop;

+


+


+

Keep in mind that repeated streamifying of a PS is just like resuming a Stream (yes, PS behaves like ... a Stream).

+

For getting a Stream to start at the beginning as defined by the Pattern enclosed by the PS,

+

you'd have to generate a new PS, e.g. by reevaluating its definition or wrapping 

+

it into a Function.

+


+


+

p = PS(Pseries(), 5);

+


+

// evaluate more than once

+


+

p.asStream.all;

+


+


+


+

// compare

+


+

q = { PS(Pseries(), 5) };

+


+

// evaluate more than once

+


+

q.value.asStream.all;

+


+


+


+

For recursively generating data see PSrecur. Referring to buffered last values of a PS can 

+

easily be done with method .at.

+


+


+

// canonical brown movement

+

// define 3 voices refering to a PS

+

// use separate PS to collect data

+

// plot

+


+

(

+

p = PS(Pbrown(65, 90, 2.1), inf, 16);

+

p.iter.nextN(16);

+


+

q = Pfunc { p[5] - 7 };

+

r = Pfunc { p[10] - 14 };

+

t = Pfunc { p[15] - 21 };

+


+

u = PS(Ptuple([p,q,r,t]), bufSize: 100);

+


+

a = Plotter().superpose_(true).plotMode_(\plines);

+

a.value = u.iter.nextN(100).flop

+

)

+


+

// playback stored pitches

+


+

(

+

v = Pbind(

+

\midinote, Pseq(u.bufSeq),

+

\dur, 0.2

+

).trace.play

+

)

+


+


+


+


+ + diff --git a/Help/PSPdiv.html b/Help/PSPdiv.html new file mode 100755 index 0000000..2985506 --- /dev/null +++ b/Help/PSPdiv.html @@ -0,0 +1,542 @@ + + + + + + + + + + + +

PSPdiv dynamic multi-layer pulse divider 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pspawner

+


+

See also: Pspawner, Sieves and Psieve patterns, Buffer Granulation, Live Granulation

+


+

PSPdiv controls the timing of one or several layers of event patterns by a single pulse pattern. In every layer single pulse durations or integer multiples ('division bases') of pulse durations can be divided by Integers or proportionally. For every layer the event pattern data can be given as event pattern or a function, which is generating an event pattern for every divisional operation. Division bases and divisions as well as the pulse itself can be controlled by patterns. 

+

PSPdiv is built on Pspawner and therefore allows sequential or parallel spawning: the type of embedding can be sequenced by a pattern for every divisional operation. So a single layer alone can produce a number of overlapping sequences.

+


+

Time division in space notation scheme with two layers and embedding of sequential type:

+


+

attachments/PSPdiv/PSPdiv_graph_1.png

+

+

A sequence of regular or irregular pulses is given as pattern of floats, these durations are marked as proportional spaces in the graphic. The sequence of divBases collects groups of pulses and divides them according to the sequence of divs. The resulting durations of each layer are again marked by proportional spacing, common entry points of layers are marked by emphasized vertical lines.

+


+

Special thanks to Ron Kuivila for developing Pspawner, it's such a versatile class !

+


+


+

Creation / Class Methods

+


+

*new (pulse, evPat, div, divBase, divType)

+

+

Creates a new PSPdiv object.

+

+

pulse - Duration or pattern of durations, given as beats. Defaults to 1.

+

+

evPat - An event pattern, a Function generating event patterns or: a SequenceableCollection thereof.

+

If an event pattern is given, the durations of the current division, calculated from current values of 

+

pulse, div and divBase, are inserted with the 'dur' key, there's no use in passing durations in

+

the event pattern in this case.

+

If a Function is given, it will be passed 4 arguments:

+

.) an array of durations of the current division, based on the following arguments

+

.) the current division number div

+

.) the current division base number divBase

+

.) the current division type divType ('seq' or 'par')

+

The Function should return the event pattern to be scheduled for this division. The typical

+

application would be using the array of durations in a Pseq with repeats = 1 as 'dur' value, 

+

though you are free to let it return any kind of event pattern.

+

Layers are slightly shifted, so that the event from a pattern of lower index is calculated

+

before an event from a pattern of higher index, if events are scheduled to happen at the same time.

+


+

div - Integer or array of array of numbers, determining a division of divBase * pulse beats or

+

a pattern returning such or: a SequenceableCollection thereof. Defaults to 1.

+

A single array of numbers is interpreted as indicator for several layers (see note below),

+

hence the doubled array is necessary for a proportional division.

+

+

divBase - Integer determining the number of multiples of pulse to be used as base of division or

+

a pattern returning such or: a SequenceableCollection thereof. Defaults to 1.

+


+

divType - Symbol 'seq' or 'par' or or a pattern returning such or: a SequenceableCollection thereof. 

+

Defaults to 'seq'. Determines the type of embedding according to Pspawner's convention.

+

+

NOTE: If one of the arguments evPat, div, divBase and divType is passed as SequenceableCollection of size > 1,

+

a multitude of layers is assumed and the other args are interpreted accordingly. To avoid ambiguities only one

+

size > 1 is allowed at maximum amongst these args (but more than one of them can be a SequenceableCollection

+

of this size). Consequently a proportional div arg for one layer must be passed in double brackets.

+


+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Ex. 1:   Basic functionality with one layer

+


+


+

// test SynthDef

+


+

(

+

SynthDef(\varKlank, { |freq = 500, att = 0.01, rel = 0.1, sourceType = 0,

+

ringtime = 1, pan = 0, amp = 0.1|

+

var sig, source = Select.ar(sourceType, [

+

BrownNoise.ar(0.05),

+

Impulse.ar(0)

+

]);

+

sig = DynKlank.ar(`[freq * (1..8), amp * (8..1)/8, ringtime * (1!8)], source);

+

sig = Splay.ar(sig);

+

OffsetOut.ar(0, Balance2.ar(sig[0], sig[1], pan) *

+

EnvGen.ar(Env.perc(att, rel), doneAction: 2))

+

}).add;

+

)

+


+


+

(

+

// base pattern, no need to provide durations, as they are calculated from other PSPdiv args

+

p = Pbind(

+

\instrument, \varKlank,

+

\midinote, Pwhite(65, 90),

+

\amp, 0.1,

+

\att, Pwhite(0.005, 0.02),

+

\rel, 2,

+

\sourceType, 1,

+

\ringtime, 2,

+

\pan, Pwhite(-0.3, 0.3)

+

);

+

)

+


+


+


+

// div = 1, pulse not divided

+


+

x = PSPdiv(0.8, p, 1).play;

+


+

x.stop

+


+


+

// div as array of two items leads to expansion into two layers

+


+

x = PSPdiv(0.8, p, [2, 1]).play;

+


+

x.stop

+


+


+

// here div is interpreted as proportion for one layer

+


+

x = PSPdiv(0.8, p, [[3, 1]] ).play;

+


+

x.stop

+


+


+

// specifying per layer

+


+

x = PSPdiv(0.8, [p, Pbindf(p, \rel, 0.1)], [1, [3, 2, 1]] ).play;

+


+

x.stop

+


+


+


+

// use with PL proxies

+


+

(

+

// defaults, want to replace later on

+

~pulse = 0.8;

+

~div = 1;

+

~divBase = 1;

+

~divType = \seq;

+


+

q = PSPdiv(PL(\pulse), p, PL(\div), PL(\divBase), PL(\divType));

+

)

+


+


+


+

// start playing

+


+

x = q.play

+


+


+

// replace on the fly:

+

// alternating tuplets

+


+

~div = PLseq([2, 3]);

+


+


+

// "dotted" notes, now we don't need double brackets as above as it's the source of the PL,

+

// not the PSPdiv arg

+


+

~div = [3, 1];

+


+


+

// acceleration and deceleration by pulse pattern control

+


+

~pulse = Pseg(PLseq([0.8, 0.3]), 10)

+


+


+

(

+

// use divBase for base length control of tuplets

+

// here this could be written with div sequencing only also

+


+

~pulse = 1;

+


+

~div = PLseq([2, 6]);

+


+

~divBase = PLseq([1, 1, 2]);

+

)

+


+


+

x.stop

+


+


+


+


+

Ex. 2:   Parallel embedding with one layer

+


+

// SynthDef from Ex. 1

+


+

(

+

// default values for proxies

+


+

~pulse = 0.5;

+

~div = PLseq([6, 4]);

+

~divBase = 2;

+

~divType = \par;

+


+


+

// evPat argument now given as Function

+

// this especially makes sense in combination with parallel embedding

+

// otherwise parallel patterns would poll event data from a single event stream

+


+


+

p = { |durs|

+

// use durs calculated from pulse, div and divBase

+

var size = durs.size;

+

Pbind(

+

\dur, Pseq(durs),

+

\instrument, \varKlank,

+

\midinote, Pseq(~baseStream.next + rrand(0, 7) + (0..size)),

+

\amp, 0.1,

+

\att, Pwhite(0.005, 0.02),

+

\rel, ~releaseStream.next,

+

\ringtime, 2,

+

\sourceType, 1,

+

\pan, ~panStream.next

+

)

+

};

+


+

// these streams deliver items for each embedding

+


+

~baseStream = PLseq([60, 70, 80]).iter;

+

~releaseStream = Pn(Pshuf([2, 0.6, 0.2])).iter;

+

~panStream = Pwhite(-0.8, 0.8).iter;

+


+


+

// we still have only one layer, but it will overlap

+


+

q = PSPdiv(PL(\pulse), p, PL(\div), PL(\divBase), PL(\divType));

+

)

+


+


+

// start

+


+

x = q.play

+


+


+

// change to sequential embedding

+


+

~divType = \seq;

+


+


+

// type of embedding can be sequenced too

+


+

~divType = PLrand([\seq, \par, \par]);

+


+


+

// default divBase was 2, allow shorter division bases

+


+

~divBase = PLrand([1, 2]);

+


+


+

x.stop

+


+


+


+

Ex. 3:   Ornamenting a line with a second layer

+


+


+

// SynthDef from Ex. 1

+


+

(

+

p = Pbind(

+

\instrument, \varKlank,

+

// basic melodic line, data stored in variable for use by ornamentation

+

\midinote, (Pn(Pshuf([72, 74, 76, 79, 81])).collect { |x| ~m = x; }) +

+

// random broadening of line

+

PLrand([[-14, 0], [0, 14]]),

+

\amp, 0.15,

+

\att, Pwhite(0.01, 0.02),

+

\rel, 3,

+

\sourceType, 1,

+

\ringtime, 3,

+

\pan, Pwhite(-0.3, 0.3)

+

);

+


+

~releaseStream = Pn(Pshuf([2, 0.5, 0.2])).iter;

+

~panStream = Pwhite(-0.8, 0.8).iter;

+

~dirStream = PLseq([1, -1]).iter;

+


+

// defines trill pattern for every event from melodic line

+


+

q = { |durs|

+

// use durs calculated from pulse, div and divBase

+

var size = durs.size, midibase = ~m;

+

Pbind(

+

\dur, Pseq(durs),

+

\instrument, \varKlank,

+

// define trill alternating above and below basic melodic line

+

\midinote, Pn(rrand(4, 9) * ~dirStream.next, size) + PLseq([0, 1]) + midibase,

+

\amp, 0.1,

+

\att, Pwhite(0.005, 0.02),

+

\rel, ~releaseStream.next,

+

\ringtime, 2,

+

\sourceType, 1,

+

\pan, ~panStream.next

+

)

+

};

+


+

// default values for PL proxies, want to replace later on

+


+

~pulse = PLshufn([1, 1, 2]/2);

+

~div = PLrand([4, 6, 8]);

+

~divBase = 1;

+

~divType = \seq;

+


+

r = PSPdiv(

+

PL(\pulse),

+

[p, q],

+

[1, PL(\div)],

+

[1, PL(\divBase)],

+

[1, PL(\divType)]

+

);

+

)

+


+


+

// start with sequential embedding: trill on every note, variuos divisions

+


+

x = r.play

+


+


+

// change to parallel embedding of trills, overlapping

+


+

(

+

~divBase = 2;

+

~div = PLrand([8, 12, 16]);

+

~divType = \par;

+

)

+


+

x.stop

+


+


+


+

Ex. 4:   Polyrhythmics of several layers

+


+


+

// SynthDef from Ex. 1

+

// three layers using varying pentatonic scales shifted by sixth tones

+


+

(

+

// staccato layer

+

p = Pbind(

+

\instrument, \varKlank,

+

\midinote, PLshufn([0, 2, 4, 7, 9]) + Pn(Pstutter(15, Pwhite(80, 100, 1))) +

+

0.6 + [0, -14],

+

// use some rests

+

\amp, 0.06,

+

\att, Pwhite(0.01, 0.02),

+

\rel, 0.15,

+

\sourceType, 1,

+

\ringtime, 3,

+

\pan, Pwhite(-0.3, 0.3)

+

);

+


+

// long release layer

+

q = Pbind(

+

\instrument, \varKlank,

+

\midinote, PLshufn([0, 2, 4, 7, 9]) + Pn(Pstutter(20, Pwhite(60, 80, 1))) +

+

PLrand([[-14, 0]]) + PLrand([0, 12]),

+

\amp, 0.08,

+

\att, Pwhite(0.01, 0.02),

+

\rel, 2,

+

\sourceType, 1,

+

\ringtime, 2,

+

\pan, Pwhite(-0.3, 0.3)

+

);

+


+

// "drum" layer

+

r = Pbind(

+

\instrument, \varKlank,

+

\midinote, PLshufn([0, 2, 4, 7, 9]) + Pn(Pstutter(25, Pwhite(35, 50, 1))) +

+

0.3 + [-12, 0],

+

\amp, 0.02,

+

\att, Pwhite(0.01, 0.02),

+

\rel, 0.35,

+

\sourceType, 0,

+

\ringtime, 1,

+

\pan, Pwhite(-0.3, 0.3)

+

);

+


+

// default values for PL proxies, want to replace later on

+


+

~pulse = PLshufn([1, 1, 2] * 5/9);

+


+

~div0 = PLshufn([4, 8]);

+

~div1 = PLshufn([2, 3, 4]);

+

~div2 = PLshufn([2, 4]);

+

~divBase = 1;

+

~divType = \seq;

+


+

u = PSPdiv(

+

PL(\pulse),

+

[p, q, r],

+

[PL(\div0), PL(\div1), PL(\div2)],

+

// will be exapanded to array of 3 PLs with same symbol reference

+

PL(\divBase),

+

PL(\divType)

+

);

+

)

+


+


+

// start

+


+

x = u.play

+


+


+

// vary pulse

+


+

~pulse = PLshufn([1, 1.5, 2.5, 3] * 5/9);

+


+

~pulse = 1;

+


+

~div0 = PLshufn([4, 6, 8]);

+


+

~div2 = PLshufn([2, 4, 6]);

+


+

~pulse = PLshufn([1, 1, 9/8]);

+


+

x.stop;

+


+


+


+

Ex. 5:   Granulation, control of many layers  

+


+

// SynthDef from Ex. 1

+


+

(

+

~amp = 0.05;

+

~att = 0.005;

+

~rel = 0.05;

+

~sourceType = 0;

+

~ringtime = 1;

+


+

~pan = PLseq([0.8, -0.8]);

+


+

// Pbind generator, patterns will stick to midinotes

+

p = { |midinote| Pbind(

+

\instrument, \varKlank,

+

\midinote, midinote,

+

\amp, PL(\amp),

+

\att, PL(\att),

+

\rel, PL(\rel),

+

\sourceType, PL(\sourceType),

+

\ringtime, PL(\ringtime),

+

\pan, PL(\pan)

+

) };

+


+

// produce an array of Pbinds, covering a whole tone cluster 

+

q = ((1, 3..51) + 40).collect(p.(_));

+


+

~size = q.size;

+


+

// same pattern source for each PL, 

+

// but for each midinote divisions per pulse can vary

+


+

~div = Pfunc { (2 ** (1..4)).choose.asInteger };

+

~divBase = 1;

+


+

~pulse = 1;

+

~rel = 0.015;

+

~sourceType = 1;

+


+

// as q is an array the args 'div' and 'divBase' will be expanded to arrays

+

u = PSPdiv(PL(\pulse), q, PL(\div), PL(\divBase));

+

)

+


+


+


+

x = u.play

+


+

// this setting exchanges the source of all PL patterns expanded as 'div' arg

+


+

~div = Pfunc { (2 ** (1..6)).choose.asInteger }

+


+


+

// also with divBase, layers are decorrelated as each stream from this pattern acts differently

+


+


+

~divBase = PLrand([1, 2])

+


+

~divBase = PLrand([1, 2, 3])

+


+


+

~pulse = 1/4

+


+

x.stop

+


+


+


+


+


+ + diff --git a/Help/PSVdif.html b/Help/PSVdif.html new file mode 100755 index 0000000..287c092 --- /dev/null +++ b/Help/PSVdif.html @@ -0,0 +1,82 @@ + + + + + + + + + + + +

PSVdif Sieve pattern for difference of integer generators with point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for difference of integer generators with point output. Corresponds to Sieve's method 'dif'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVdif object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+

Examples

+


+


+

p = PSVdif([3, 2], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 30)

+


+

q = PSVdif([1, a], 20)

+


+

q.asStream.all

+


+


+

r = PSVdif([1, a], limit: 15)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVdif_i.html b/Help/PSVdif_i.html new file mode 100755 index 0000000..e1727c4 --- /dev/null +++ b/Help/PSVdif_i.html @@ -0,0 +1,82 @@ + + + + + + + + + + + +

PSVdif_i Sieve pattern for difference of integer generators with interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for difference of integer generators with interval output. Corresponds to Sieve's method 'dif_i'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVdif_i object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned until default summation limit of 65536.

+


+


+


+

Examples

+


+


+

p = PSVdif_i([3, 2], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 30)

+


+

q = PSVdif_i([1, a], 20)

+


+

q.asStream.all

+


+


+

r = PSVdif_i([1, a], limit: 15)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVdif_o.html b/Help/PSVdif_o.html new file mode 100755 index 0000000..cb2811f --- /dev/null +++ b/Help/PSVdif_o.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVdif_o Sieve pattern for difference of integer generators with offsets and point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for difference of integer generators with offsets and point output. Corresponds to Sieve's method 'dif_o'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVdif_o object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+

Examples

+


+


+

p = PSVdif_o([3, 1, 5, -2], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVdif_o([a, 90, 3, 80], 20)

+


+

q.asStream.all

+


+


+

r = PSVdif_o([a, 90, 3, 80], limit: 100)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVdif_oi.html b/Help/PSVdif_oi.html new file mode 100755 index 0000000..c0691f0 --- /dev/null +++ b/Help/PSVdif_oi.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVdif_oi Sieve pattern for difference of integer generators with offsets and interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for difference of integer generators with offsets and interval output. Corresponds to Sieve's method 'dif_oi'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVdif_oi object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned up to default summation limit of 65536.

+


+


+


+

Examples

+


+


+

p = PSVdif_oi([5, 0, 10, -20], 20)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVdif_oi([1, 0, a, -2], 20)

+


+

q.asStream.all

+


+


+

r = PSVdif_oi([1, 0, 10, -2], limit: 20)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVop.html b/Help/PSVop.html new file mode 100755 index 0000000..293b271 --- /dev/null +++ b/Help/PSVop.html @@ -0,0 +1,105 @@ + + + + + + + + + + + +

PSVop Sieve pattern for arbitrary set operations of integer generators with point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for arbitrary set operations of integer generators with point output. 

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, op, difIndex, maxLength, limit)

+

+

Creates a new PSVop object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+


+

op - One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union',

+

'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'.

+


+

difIndex - Integer or a Pattern/Stream to produce such. 

+

Determines the generator from which will be subtracted in case of operation 'dif'.

+

Defaults to 0.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+

Examples

+


+


+

// equivalent

+


+

x = PSVop([3, 5], \sd)

+

y = PSVsymdif([3, 5])

+


+

x.asStream.nextN(15)

+

y.asStream.nextN(15)

+


+


+

// sequencing of logical operations

+


+

p = PSVop([3, 3], Pseq([\u, \sd], inf))

+


+

p.asStream.nextN(15)

+


+


+

// specify difference

+


+

q = PSVop([2, 5], \d, 1)

+


+

q.asStream.nextN(100)

+


+


+

r = PSVop([2, 5], \d, 0)

+


+

r.asStream.nextN(100)

+


+


+


+ + diff --git a/Help/PSVop_i.html b/Help/PSVop_i.html new file mode 100755 index 0000000..39c410a --- /dev/null +++ b/Help/PSVop_i.html @@ -0,0 +1,105 @@ + + + + + + + + + + + +

PSVop_i Sieve pattern for arbitrary set operations of integer generators with interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for arbitrary set operations of integer generators with interval output. 

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, op, difIndex, maxLength, limit)

+

+

Creates a new PSVop_i object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+


+

op - One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union',

+

'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'.

+


+

difIndex - Integer or a Pattern/Stream to produce such. 

+

Determines the generator from which will be subtracted in case of operation 'dif'.

+

Defaults to 0.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned until default summation limit of 65536.

+


+


+


+

Examples

+


+


+

// equivalent

+


+

x = PSVop_i([3, 5], \sd)

+

y = PSVsymdif_i([3, 5])

+


+

x.asStream.nextN(15)

+

y.asStream.nextN(15)

+


+


+

// sequencing of logical operations

+


+

p = PSVop_i([3, 3], Pseq([\u, \sd], inf))

+


+

p.asStream.nextN(15)

+


+


+

// specify difference

+


+

q = PSVop_i([2, 5], \d, 1)

+


+

q.asStream.nextN(100)

+


+


+

r = PSVop_i([2, 5], \d, 0)

+


+

r.asStream.nextN(100)

+


+


+ + diff --git a/Help/PSVop_o.html b/Help/PSVop_o.html new file mode 100755 index 0000000..36cf6a5 --- /dev/null +++ b/Help/PSVop_o.html @@ -0,0 +1,108 @@ + + + + + + + + + + + +

PSVop_o Sieve pattern for arbitrary set operations of integer generators with offsets and point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for arbitrary set operations of integer generators with offsets and point output. 

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, op, difIndex, maxLength, limit)

+

+

Creates a new PSVop_o object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

Offsets must be integers.

+


+

op - One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union',

+

'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'.

+


+

difIndex - Integer or a Pattern/Stream to produce such. 

+

Determines the generator from which will be subtracted in case of operation 'dif'.

+

Defaults to 0.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+

Examples

+


+


+

// equivalent

+


+

x = PSVop_o([3, 1, 5, 0], \sd)

+

y = PSVsymdif_o([3, 1, 5, 0])

+


+

x.asStream.nextN(15)

+

y.asStream.nextN(15)

+


+


+

// sequencing of logical operations

+


+

p = PSVop_o([3, 1, 2, 0], Pseq([\s, \u, \u], inf))

+


+

p.asStream.nextN(15)

+


+


+

// specify difference

+


+

q = PSVop_o([3, 1, 5, 0], \d, 1)

+


+

q.asStream.nextN(10)

+


+


+

r = PSVop_o([3, 1, 5, 0], \d, 0)

+


+

r.asStream.nextN(10)

+


+


+


+


+ + diff --git a/Help/PSVop_oi.html b/Help/PSVop_oi.html new file mode 100755 index 0000000..245769a --- /dev/null +++ b/Help/PSVop_oi.html @@ -0,0 +1,110 @@ + + + + + + + + + + + +

PSVop_oi Sieve pattern for arbitrary set operations of integer generators with offsets and interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for arbitrary set operations of integer generators with offsets and interval output. 

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o 

+


+


+

Creation / Class Methods

+


+

*new (genList, op, difIndex, maxLength, limit)

+

+

Creates a new PSVop_oi object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

Offsets must be integers.

+


+

op - One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union',

+

'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'.

+


+

difIndex - Integer or a Pattern/Stream to produce such. 

+

Determines the generator from which will be subtracted in case of operation 'dif'.

+

Defaults to 0.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned up to default summation limit of 65536.

+


+


+


+


+

Examples

+


+


+


+

// equivalent

+


+

x = PSVop_oi([3, 1, 5, 0], \sd)

+

y = PSVsymdif_oi([3, 1, 5, 0])

+


+

x.asStream.nextN(15)

+

y.asStream.nextN(15)

+


+


+

// sequencing of logical operations

+


+

p = PSVop_oi([3, 1, 2, 0], Pseq([\s, \u, \u], inf))

+


+

p.asStream.nextN(15)

+


+


+

// specify difference

+


+

q = PSVop_oi([3, 1, 5, 0], \d, 1)

+


+

q.asStream.nextN(10)

+


+


+

r = PSVop_oi([3, 1, 5, 0], \d, 0)

+


+

r.asStream.nextN(10)

+


+


+


+


+


+ + diff --git a/Help/PSVsect.html b/Help/PSVsect.html new file mode 100755 index 0000000..c684b08 --- /dev/null +++ b/Help/PSVsect.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVsect Sieve pattern for intersection of integer generators with point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for intersection of integer generators with point output. Corresponds to Sieve's method 'sect'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsect object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+


+

Examples

+


+


+

p = PSVsect([3, 5], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 1000)

+


+

q = PSVsect([a, 100], 10)

+


+

q.asStream.all

+


+


+

r = PSVsect([a, 100], limit: 500)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVsect_i.html b/Help/PSVsect_i.html new file mode 100755 index 0000000..3b8c4e0 --- /dev/null +++ b/Help/PSVsect_i.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVsect_i Sieve pattern for intersection of integer generators with interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for intersection of integer generators with interval output. Corresponds to Sieve's method 'sect_i'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsect_i object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned until default summation limit of 65536.

+


+


+


+

Examples

+


+


+

p = PSVsect_i([3, 5], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 1000)

+


+

q = PSVsect_i([a, 100], 10)

+


+

q.asStream.all

+


+


+

r = PSVsect_i([a, 100], limit: 500)

+


+

r.asStream.all

+


+


+ + diff --git a/Help/PSVsect_o.html b/Help/PSVsect_o.html new file mode 100755 index 0000000..d5e2102 --- /dev/null +++ b/Help/PSVsect_o.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVsect_o Sieve pattern for intersection of integer generators with offsets and point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for intersection of integer generators with offsets and point output. Corresponds to Sieve's method 'sect_o'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsect_o object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+

Examples

+


+


+

p = PSVsect_o([3, 1, 5, -2], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 200)

+


+

q = PSVsect_o([a, 90, 10, 100], 20)

+


+

q.asStream.all

+


+


+

r = PSVunion_o([a, 50, 10, -100], limit: 100)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVsect_oi.html b/Help/PSVsect_oi.html new file mode 100755 index 0000000..f399d6f --- /dev/null +++ b/Help/PSVsect_oi.html @@ -0,0 +1,82 @@ + + + + + + + + + + + +

PSVsect_oi Sieve pattern for intersection of integer generators with offsets and interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for intersection of integer generators with offsets and interval output. Corresponds to Sieve's method 'sect_oi'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsect_oi object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned up to default summation limit of 65536.

+


+


+

Examples

+


+


+

p = PSVsect_oi([10, 31, 50, 1], 20)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVsect_oi([a, 20, 10, 0], 5)

+


+

q.asStream.all

+


+


+

r = PSVsect_oi([a, 20, 10, 0], limit: 25)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVsymdif.html b/Help/PSVsymdif.html new file mode 100755 index 0000000..ea64001 --- /dev/null +++ b/Help/PSVsymdif.html @@ -0,0 +1,82 @@ + + + + + + + + + + + +

PSVsymdif Sieve pattern for symmetric difference of integer generators with point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for symmetric difference of integer generators with point output. Corresponds to Sieve's method 'symdif'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsymdif object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+

Examples

+


+


+

p = PSVsymdif([3, 5], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 50)

+


+

q = PSVsymdif([a, 2], 15)

+


+

q.asStream.all

+


+


+

r = PSVsymdif([a, 2], limit: 20)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVsymdif_i.html b/Help/PSVsymdif_i.html new file mode 100755 index 0000000..30e5255 --- /dev/null +++ b/Help/PSVsymdif_i.html @@ -0,0 +1,84 @@ + + + + + + + + + + + +

PSVsymdif_i Sieve pattern for symmetric difference of integer generators with interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for symmetric difference of integer generators with interval output. Corresponds to Sieve's method 'symdif_i'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsymdif_i object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned until default summation limit of 65536.

+


+


+


+

Examples

+


+


+

p = PSVsymdif_i([3, 5], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 30)

+


+

q = PSVsymdif_i([a, 100], 10)

+


+

q.asStream.all

+


+


+

r = PSVsymdif_i([a, 100], limit: 1000)

+


+

r.asStream.all

+


+


+


+ + diff --git a/Help/PSVsymdif_o.html b/Help/PSVsymdif_o.html new file mode 100755 index 0000000..0e56efd --- /dev/null +++ b/Help/PSVsymdif_o.html @@ -0,0 +1,84 @@ + + + + + + + + + + + +

PSVsymdif_o Sieve pattern for symmetric difference of integer generators with offsets and point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for symmetric difference of integer generators with offsets and point output. Corresponds to Sieve's method 'symdif_o'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsymdif_o object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+


+

Examples

+


+


+

p = PSVunion_o([3, 1, 5, -2], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVunion_o([a, 90, 10, 100], 20)

+


+

q.asStream.all

+


+


+

r = PSVsymdif_o([a, 90, 10, 80], limit: 100)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVsymdif_oi.html b/Help/PSVsymdif_oi.html new file mode 100755 index 0000000..876f69e --- /dev/null +++ b/Help/PSVsymdif_oi.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVsymdif_oi Sieve pattern for symmetric difference of integer generators with offsets and interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for symmetric difference of integer generators with offsets and interval output. Corresponds to Sieve's method 'symdif_oi'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVsymdif_oi object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned up to default summation limit of 65536.

+


+


+


+

Examples

+


+


+

p = PSVsymdif_oi([10, 0, 50, 1], 20)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVsymdif_oi([a, 0, 10, 100], 20)

+


+

q.asStream.all

+


+


+

r = PSVsymdif_oi([a, 0, 10, 100], limit: 120)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVunion.html b/Help/PSVunion.html new file mode 100755 index 0000000..7e18719 --- /dev/null +++ b/Help/PSVunion.html @@ -0,0 +1,81 @@ + + + + + + + + + + + +

PSVunion Sieve pattern for union of integer generators with point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for union of integer generators with point output. Corresponds to Sieve's method 'union'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVunion object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+

Examples

+


+


+

p = PSVunion([3, 5], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 30)

+


+

q = PSVunion([a, 100], 10)

+


+

q.asStream.all

+


+


+

r = PSVunion([a, 100], limit: 1000)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVunion_i.html b/Help/PSVunion_i.html new file mode 100755 index 0000000..c6d8fa0 --- /dev/null +++ b/Help/PSVunion_i.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +

PSVunion_i Sieve pattern for union of integer generators with interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for union of integer generators with interval output. Corresponds to Sieve's method 'union_i'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVunion_i object.

+

+

genList - An array of generators. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned until default summation limit of 65536.

+


+


+


+


+

Examples

+


+


+

p = PSVunion_i([3, 5], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(7, 30)

+


+

q = PSVunion_i([a, 100], 10)

+


+

q.asStream.all

+


+


+

r = PSVunion_i([a, 100], limit: 1000)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVunion_o.html b/Help/PSVunion_o.html new file mode 100755 index 0000000..7fd73cd --- /dev/null +++ b/Help/PSVunion_o.html @@ -0,0 +1,84 @@ + + + + + + + + + + + +

PSVunion_o Sieve pattern for union of integer generators with offsets and point output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for union of integer generators with offsets and point output. Corresponds to Sieve's method 'union_o'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVunion_o object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which integers can be returned by the stream.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+


+


+


+

Examples

+


+


+

p = PSVunion_o([3, 1, 5, -2], 10)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVunion_o([a, 90, 10, 100], 20)

+


+

q.asStream.all

+


+


+

r = PSVunion_o([a, 10, 3, 7], limit: 20)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSVunion_oi.html b/Help/PSVunion_oi.html new file mode 100755 index 0000000..d377410 --- /dev/null +++ b/Help/PSVunion_oi.html @@ -0,0 +1,84 @@ + + + + + + + + + + + +

PSVunion_oi Sieve pattern for union of integer generators with offsets and interval output

+


+

Part of: miSCellaneous

+


+

Inherits from: Psieve

+


+

Pattern for union of integer generators with offsets and interval output. Corresponds to Sieve's method 'union_oi'.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*new (genList, maxLength, limit)

+

+

Creates a new PSVunion_oi object.

+

+

genList - An array of generators and corresponding offsets. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

Offsets must be integers.

+


+

maxLength - Integer. Maximum number of items, which the stream will return.

+

Defaults to inf.

+


+

limit - Integer. Limit up to which intervals can be returned by the stream.

+

If no limit is passed, integer intervals might be returned up to default summation limit of 65536.

+


+


+


+


+

Examples

+


+


+

p = PSVunion_oi([10, 0, 50, 1], 20)

+


+

p.asStream.nextN(15)

+


+


+

a = Sieve(4, 20)

+


+

q = PSVunion_oi([a, 0, 10, 100], 20)

+


+

q.asStream.all

+


+


+

r = PSVunion_oi([a, 0, 10, 100], limit: 120)

+


+

r.asStream.all

+


+ + diff --git a/Help/PSdup.html b/Help/PSdup.html new file mode 100755 index 0000000..0c38a3e --- /dev/null +++ b/Help/PSdup.html @@ -0,0 +1,205 @@ + + + + + + + + + + + +

PSdup Pattern which returns last values from other patterns via PSx

+


+

Part of: miSCellaneous

+


+

Inherits from: PS / PStream

+


+

See also: MemoRoutine, PSx stream patterns, PS, PSrecur, PSloop

+


+


+

PSdup uses the storage functionality of other PSx patterns. To track a value stream or event stream from a pattern you'd have to wrap the pattern into a PSx.

+


+


+

Creation / Class Methods

+


+

*new (psxPat, length, bufSize, copyItems, copySets)

+

+

Creates a new PSdup object.

+

+

psxPat - Source pattern, must be a PSx pattern.

+

length - Number of output items, may be pattern or stream, defaults to inf.

+

bufSize - Size of buffer to store last values, defaults to 1.

+

copyItems - Determines if and how to copy the last items from psxPat's buffer

+

which are either non-Sets or member of Sets. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). 

+

Other values are interpreted as 0. Defaults to 0.

+

0: original item 

+

1: copy item

+

2: deepCopy item

+

copySets - Determines if and how to copy the last items from psxPat's buffer

+

which are Sets. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). 

+

Other values are interpreted as 0. Defaults to 1.

+

0: original Set 

+

1: copy Set

+

+

NOTE 1: The distinction of copying items and sets makes sense in the case of event streams.

+

Per default Events are copied (copySets == 1), not their values (copyItems == 0). 

+

By playing Events those are used to store additional data (synth ids, msgFuncs …) 

+

which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use 

+

MemoRoutine - copied Events will not contain this additional data. 

+

If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured 

+

then copying makes no sense, this is the normal case, so copyItems defaults to 0.

+

When going to alter the ouput, you might want to set copyItems to 1 for a PSx returning 

+

simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set

+

copySets to 1 and copyItems to 2 (an option copySets == 2 doesn't exist as

+

it would be contradictory in combination with copyItems < 2).

+


+

NOTE 2: Copy options concern copying into PSdup's buffer as well as 

+

the output of a Stream derived from the PSdup. When such a Stream is outputting copies 

+

this prevents unintended altering of items stored in the buffer of psxPat. On the other hand

+

storing copies in PSdup's buffer prevents these from being altered unintendedly.

+


+


+

Instance Methods

+


+

psxPat, psxPat_(value)

+

+

Instance variable getter and setter methods. 

+


+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// copying of value patterns

+

// PSdup needs a PSx as input, as its value storage is used,

+

// so it's easiest to wrap the original pattern into a PS

+


+

(

+

p = PS(Pseries());

+

q = PSdup(p);

+


+

// PSx patterns have a state and, in this regard, behave like Streams.

+

// However, like other Patterns, for generating they must be made to Streams 

+

// which are the objects actually returning items. 

+


+

x = p.asStream;

+

y = q.asStream;

+

)

+


+

// y follows x (as in the array left is evaluated before right) 

+


+

(

+

a = [];

+

10.do { a = a.add([x.next, y.next]) };

+

a;

+

)

+


+


+

// get values from original Pattern / Stream

+


+

x.nextN(10)

+


+

// now y copies the last value of x resp. p

+


+

y.nextN(10)

+


+


+


+

// data sharing with event patterns

+


+

(

+

p = Pbind(

+

\midinote, Pwhite(60, 90) + PLrand([0, 0, [0, -3]]),

+

\dur, PLrand([0.2, 0.4]),

+

\amp, PLrand([0.07, 0.12, 0.2]),

+

\type, Pfunc { 0.1.coin.if { \rest }{ \note } },

+

\pan, 1

+

);

+


+

q = PS(p);

+


+

// use PSdup as base for alterings

+

// it takes the last event stored in PS(p)

+


+

r = Pbindf(Padd(\midinote, PLrand([1,2,4,5]), PSdup(q)), \pan, -1);

+


+

// as in general with event stream data sharing it's recommended to invent a small delta 

+

// between streams, here this is extended to a clear echo 

+


+

t = Ptpar([0, q, 0.1, r]).trace.play;

+

)

+


+

t.stop;

+


+


+

// data sharing with event patterns, more voices 

+


+


+

(

+

p = Pbind(

+

\midinote, Pwhite(50.0, 65),

+

\dur, PLrand([0.7, 0.9, 1.2]),

+

\amp, PLrand([0.1, 0.15, 0.2]),

+

\legato, 0.1

+

);

+


+

q = PS(p);

+


+

// make pattern maker Function for parametrized alterings

+


+

f = { |div, add| Padd(\midinote, add, Pmul(\dur, 1 / div, PSdup(q))) };

+

d = 0.001;

+


+

t = Ptpar([

+

0, q, 

+

d, f.(2, 5 + PLrand([0, [0, 12.05]])),

+

d*2, f.(4, 7 + PLrand([0, [0, 12.1]])),

+

d*3, f.(8, 10 + PLrand([0, [0, 12.2]]))

+

]).play

+

)

+


+


+

t.stop;

+


+


+


+ + diff --git a/Help/PSloop.html b/Help/PSloop.html new file mode 100755 index 0000000..5353021 --- /dev/null +++ b/Help/PSloop.html @@ -0,0 +1,725 @@ + + + + + + + + + + + +

PSloop Pattern to derive loops from a given Pattern 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pattern

+


+

See also: MemoRoutine, PSx stream patterns, PS, PSdup PSrecur

+


+


+

Although PSloop is not a subclass of PStream, instances of PSloop have a state by storing a PStream of the source pattern in an instance variable. So the specific characteristics of PSx patterns are indirectly inherited by PSloop. This especially concerns the way to generate new, fresh PSloop streams, see examples in PSx stream patterns.

+


+

Note that impossible lookBack and indices values will be clipped, see descriptions of args bufSize, lookBack and indices. 

+


+


+

Creation / Class Methods

+


+

*new (srcPat, length, bufSize, lookBack, doSkip, loopFunc, loopFuncPerItem, loopFuncAsGoFunc, goFunc, indices, copyItems, copySets)

+

+

Creates a new PSloop object.

+

+

srcPat - Source pattern for looping, can be value or event pattern.

+

length - Number of output items, may be Pattern or Stream, defaults to inf.

+


+

bufSize - Integer size of buffer to store last values. Determines and clips the maximum lookBack index. Defaults to 1.

+


+

lookBack - Non-negative Integer determining the depth of looking backwards when looping, may be Pattern or Function also.

+

Default 0 means going on with the Stream of the source pattern srcPat.

+

If no indices is given, a positive Integer lookBack = n causes straight looping from the nth item

+

in the past up to the last item of the Stream.

+

If indices is given, an index array is produced by this function applied to lookBack = n. 

+

The array refers to the nth item in the past by array index 0.

+

If lookBack values are derived from a Pattern or Function, they might be polled at the end of the loops

+

or with every item, this is determined by the current value of doSkip. 

+

lookBack will be clipped by bufSize if it is greater than the latter.

+


+

doSkip - Integer or Boolean or: Function or Stream returning such.

+

Determines if lookBack values are polled at the end of loops (0, false) or within loops (1, true) also.

+

In the latter case a new lookBack value will stop the current loop and start a new one. Defaults to 1.

+

+

loopFunc - Function or Pattern returning Functions, to be applied to items of the loops. 

+

If Functions are streamed by passing a Function-generating Pattern loopFuncPerItem determines if

+

a Function will be applied per item (1, true) or to all items of a loop (0, false).

+

When loopFunc is nil or the loopFunc stream returns nil, no Function is applied.

+

+

loopFuncPerItem - Integer or Boolean or: Function or Stream returning such.

+

If loopFunc is given, loopFuncPerItem determines if a Function will be applied per item (1, true) or 

+

to all items of a loop (0, false).

+


+

loopFuncAsGoFunc - Integer or Boolean or: Function or Stream returning such.

+

Determines if loopFunc will be used for new items outside loops too (1, true).

+

In this case goFunc is ignored (resp. nothing is polled from a goFunc stream) and nil values 

+

from the loopFunc stream are also taken over (no Function is applied outside loops then).

+

+

goFunc - Function or Pattern returning Functions, to be applied to new items outside loops. 

+

When goFunc is nil or the goFunc stream returns nil, no Function is applied.

+

Note that goFunc has no effect when loopFuncAsGoFunc determines to use loopFunc generally.

+


+

indices - SequenceableCollection, Function, or Pattern returning SequenceableCollections or Functions.

+

If no indices is passed (default nil) a positive Integer lookBack = n causes straight looping from the nth item

+

in the past up to the last item of the Stream.

+

A SequenceableCollection passed via indices is taken as array of indices and determines the items of the buffer, 

+

identifying the nth item in the past with array index 0.

+

A Function passed via indices takes lookBack = n as argument and must return an index array which also

+

determines the items of the buffer, identifying the nth item in the past with array index 0.

+

A Pattern passed via indices should be defined to generate Functions or SequenceableCollections, 

+

which are interpreted in the same way as above.

+

In case of a Pattern a new indices value is polled within a loop if current doSkip equals 1 or true.

+

indices will be clipped by lookBack - 1, lookBack itself might be clipped by bufSize.

+

+

copyItems - Argument passed to the PS wrapper of srcPat. See PS.

+

Determines if and how to copy items, which are either non-Sets or member of Sets. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). 

+

Other values are interpreted as 0. Defaults to 0.

+

0: original item 

+

1: copy item

+

2: deepCopy item

+

+

copySets - Argument passed to the PS wrapper of srcPat. See PS.

+

Determines if and how to copy Sets (and hence Events). 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). 

+

Other values are interpreted as 0. Defaults to 1.

+

0: original Set 

+

1: copy Set

+

+

NOTE 1: The distinction of copying items and sets makes sense in the case of event streams.

+

Per default Events are copied (copySets == 1), not their values (copyItems == 0). 

+

By playing Events those are used to store additional data (synth ids, msgFuncs …) 

+

which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use 

+

MemoRoutine - copied Events will not contain this additional data. 

+

If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured 

+

then copying makes no sense, this is the normal case, so copyItems defaults to 0.

+

When going to alter the ouput, you might want to set copyItems to 1 for a PSx returning 

+

simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set

+

copySets to 1 and copyItems to 2 (an option copySets == 2 doesn't exist as

+

it would be contradictory in combination with copyItems < 2).

+


+

NOTE 2: Copy options concern copying into PS's buffer as well as 

+

the output of a Stream derived from the PS. When such a Stream is outputting copies 

+

this prevents unintended altering of items stored in the buffer of the source. On the other hand

+

storing copies in PSrecur's buffer prevents these from being altered unintendedly.

+


+


+

Instance Methods

+


+

psPat, psPat(value)

+

+

Instance variable getter and setter methods. 

+

psPat  holds a Pstream with args srcPat, length, bufSize, copyItems, copySets.

+


+

lookBack, lookBack(value)

+

+

Instance variable getter and setter methods. 

+


+

doSkip, doSkip(value)

+

+

Instance variable getter and setter methods. 

+


+

loopFunc, loopFunc(value)

+

+

Instance variable getter and setter methods. 

+


+

loopFuncPerItem, loopFuncPerItem(value)

+

+

Instance variable getter and setter methods. 

+


+

loopFuncAsGoFunc, loopFuncAsGoFunc(value)

+

+

Instance variable getter and setter methods. 

+


+

goFunc, goFunc(value)

+

+

Instance variable getter and setter methods. 

+


+

indices, indices(value)

+

+

Instance variable getter and setter methods. 

+


+


+


+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Ex. 1a:   PSloop used as value pattern

+


+

// straight usage as value pattern for midinotes

+


+

(

+

// lookBack determines number of items to loop, must start with 0 (no loop),

+

// doSkip determines if loops should be completed or not with new lookBack values.

+


+

// Passing both via Functions enables to set on the fly,

+

// enable immediate loop change by setting doSkip to 1

+


+

~lookBack = 0;

+

~doSkip = true;

+


+

p = Pbind(

+

\dur, 1/5,

+

\midinote, PSloop(

+

Prand((60..80), inf), 

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

doSkip: { ~doSkip }

+

)

+

).play

+

)

+


+

// wait a bit to fill buffer

+

// keep running, set loop lengths immediately

+


+

~lookBack = 4

+


+

~lookBack = 2

+


+

~lookBack = 7

+


+


+

// change to skip per loop (default)

+


+

~doSkip = false

+


+

~lookBack = 3

+


+

~lookBack = 5

+


+

~lookBack = 9

+


+


+

// go on

+


+

~lookBack = 0

+


+

p.stop;

+


+


+


+

Ex. 1b:   PSloop used as event pattern

+


+

// rhythms are looped too

+


+

(

+

~lookBack = 0;

+

~doSkip= 1;

+


+

p = PSloop(

+

Pbind(

+

\dur, Pn(Pshuf([1, 1, 2, Pseq(2!3/3)]/5)),

+

\midinote, Prand((60..80), inf) 

+

), 

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

doSkip: { ~doSkip}

+

).play

+

)

+


+

// wait a bit to fill buffer

+

// keep running, set loop lengths immediately

+


+

~lookBack = 6

+


+

~lookBack = 5

+


+


+

// go on and loop again

+


+

~lookBack = 0

+


+

~lookBack = 7

+


+


+

p.stop;

+


+


+


+

Ex. 2a:   PSloop used as value pattern, lookBack given as pattern

+


+

// lookBack passed as pattern, 

+

// lookBack pattern must start with zeros, 

+

// otherwise it will immediately stop with buffer values = nil 

+


+

// PSloop as value pattern: in general rhythms aren't looped

+

+

(

+

p = Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, PSloop(

+

Prand((60..80), inf), 

+

bufSize: 10, 

+

lookBack: Pseq([0, 0, 0, 2, 2, 3, 3], inf)

+

)

+

).play

+

)

+


+

p.stop

+


+


+


+

Ex. 2b:   PSloop used as event pattern, lookBack given as pattern

+


+

// rhythms looped too

+


+

(

+

p = PSloop(

+

Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, Prand((60..80), inf) 

+

), 

+

bufSize: 10, 

+

lookBack: Pseq([0, 0, 0, 2, 2, 3, 3], inf)

+

).play

+

)

+


+

p.stop

+


+

+


+

Ex. 3a:   lookBack indices given as array

+


+

// With the indices arg arbitrary series from the buffer can be played.

+

// Passing an array we define an index sequence which doesn't depend on lookBack

+


+

(

+

~lookBack = 0; 

+


+

p = PSloop(

+

Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, Pseq((60..80), inf)

+

), 

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

indices: [0, 1, 0, 1, 2, 0, 1, 2, 3]

+

).trace.play

+

)

+


+

// wait a bit to fill buffer

+

// start loop with useful lookBack (here > 3)

+


+

~lookBack = 4

+


+

~lookBack = 6

+


+


+

// go on and loop again

+


+

~lookBack = 0;

+


+

~lookBack = 5

+


+


+

p.stop

+


+


+


+

Ex. 3b:   lookBack indices given as Function

+


+

// If a Function is passed to indices it takes the current lookBack arg as argument.

+


+

// mirroring the full lookBack size

+

// start without loop

+


+

(

+

~lookBack = 0;

+


+

p = PSloop(

+

Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, Prand((60..80), inf)

+

), 

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

indices: { |l| (0..l-1).mirror }

+

).trace.play

+

)

+


+

// wait a bit to fill buffer

+

// mirrored loop i.e. loop with added retrograde

+


+

~lookBack = 3

+


+


+

// go on and loop again

+


+

~lookBack = 0

+


+

~lookBack = 3

+


+

p.stop

+


+


+


+

Ex. 3c:   lookBack indices given as Pattern

+


+

// The indices arg might get a pattern which can generate Functions as well as arrays.

+

// Start with sufficient number of zeros as lookBack to fill buffer.

+


+

(

+

p = PSloop(

+

Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, Prand((60..80), inf)

+

), 

+

bufSize: 10, 

+

lookBack: Pseq([Pn(0, 7), Pstutter(4, Pwhite(3, 5, 1))], inf).trace,

+

indices: Pseq([1!2, { |l| (l-1..0).postln }], inf).trace

+

).trace.play

+

)

+


+

p.stop

+


+


+


+

Ex. 4a:   loopFunc given as Function

+


+

// a Function passed to loopFunc is applied to all items of the looping

+


+

(

+

~lookBack = 0;

+


+

p = Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, PSloop(

+

Prand((60..80), inf),

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

loopFunc: { |x| x + [0, 5] }

+

)

+

).play

+

)

+


+

// wait a bit to fill buffer

+

// loop with Function applied

+


+

~lookBack = 3

+


+

~lookBack = 6

+


+


+

// go on and stop

+


+

~lookBack = 0

+


+

p.stop

+


+


+


+

Ex. 4b:   loopFunc given as Pattern

+


+

// loopFunc also takes a pattern of Functions, in this case

+

// the arg loopFuncPerItem decides if next Functions are polled per item or per loop.

+


+

(

+

~lookBack = 0;

+

~loopFuncPerItem = true;  // or 1

+


+

p = Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, PSloop(

+

Prand((60..80), inf),

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

// every number gets a Function that adds an interval of that size

+

loopFunc: Pxrand((3..11), inf).collect { |x| { |y| y - [0, x].postln } },

+

loopFuncPerItem: { ~loopFuncPerItem }

+

)

+

).trace.play

+

)

+


+

// wait a bit to fill buffer

+

// start looping with Functions polled per item 

+


+

~lookBack = 3

+


+

~lookBack = 6

+


+


+

// one interval per loop

+


+

~loopFuncPerItem = false   // or 0

+


+

~lookBack = 9

+


+


+

// switch back to new interval per item

+


+

~loopFuncPerItem = 1

+


+


+

// go on and stop

+


+

~lookBack = 0

+


+

p.stop

+


+


+


+

Ex. 4c:   loopFunc vs. goFunc 

+


+

// Besides loopFunc a separate Function (or Pattern of Functions) can be defined for

+

// application outside loops via the goFunc arg.

+

// The arg loopFuncAsGoFunc decides if loopFunc should be taken for that task

+

// (and goFunc should be ignored in that case).

+


+

(

+

~lookBack = 0;

+

~loopFuncPerItem = false;  // one func per loop

+

~loopFuncAsGoFunc = false;  // start with dedicated goFunc

+


+

p = Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, PSloop(

+

Prand((60..80), inf),

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

// every number gets a Function that adds an interval of that size

+

loopFunc: Pxrand((3..11), inf).collect { |x| { |y| y - [0, x].postln } },

+

loopFuncPerItem: { ~loopFuncPerItem },

+

goFunc: { |x| [x, x + 2] },

+

loopFuncAsGoFunc: { ~loopFuncAsGoFunc }

+

)

+

).trace.play

+

)

+


+

// wait a bit to fill buffer

+

// start looping with Functions polled per loop 

+


+

~lookBack = 3

+


+

~lookBack = 6

+


+


+

// loop per item

+


+

~loopFuncPerItem = true

+


+


+

// prepare to use loopFunc when going on

+


+

~loopFuncAsGoFunc = true

+


+


+

// go on

+


+

~lookBack = 0

+


+


+

// switch to dedicated goFunc and stop

+


+

~loopFuncAsGoFunc = false

+


+

p.stop

+


+


+


+


+

Ex. 4d:   Turning loopFunc and goFunc on and off

+


+

// There are no separate PSloop flags needed for that:

+

// If loopFunc or goFunc return nil, no Function is applied,

+

// so suited Patterns using flags can be passed as loopFunc / goFunc args.

+


+

(

+

~lookBack = 0;

+

~loopFuncPerItem = false;  // one func per loop

+

~loopFuncAsGoFunc = false;  // start with dedicated goFunc

+


+

~turnOnLoopFunc = true;

+

~turnOnGoFunc = true;

+


+

p = Pbind(

+

\dur, Pn(Pshuf([1, 1, 2]/6)),

+

\midinote, PSloop(

+

Prand((60..80), inf),

+

bufSize: 10, 

+

lookBack: { ~lookBack },

+

// every number gets a Function that adds an interval of that size,

+

// if ~turnOnLoopFunc evaluates to false the stream returns nil instead of a Function

+

loopFunc: Pxrand((3..11), inf).collect { |x| ~turnOnLoopFunc.if { { |y| y - [0, x].postln } } },

+

loopFuncPerItem: { ~loopFuncPerItem },

+

goFunc: Pfunc { ~turnOnGoFunc.if { { |x| [x, x + 2] } } },

+

loopFuncAsGoFunc: { ~loopFuncAsGoFunc }

+

)

+

).trace.play

+

)

+


+

// wait a bit to fill buffer

+

// start looping with Functions polled per loop 

+


+

~lookBack = 3

+


+

~lookBack = 6

+


+


+

// when Functions are polled per loop, turning loopFunc off also works per loop

+


+

~turnOnLoopFunc = false

+


+


+

// use loopFunc again, namely per item

+


+

~turnOnLoopFunc = true

+


+

~loopFuncPerItem = true 

+


+


+

// now turning it off works immediately

+


+

~turnOnLoopFunc = false

+


+


+


+

// go on

+


+

~lookBack = 0

+


+


+

// as loopFunc is now turned off, this applies also when used for new values 

+


+

~loopFuncAsGoFunc = true

+


+


+

// switch to goFunc again

+


+

~loopFuncAsGoFunc = false

+


+


+

// silently turn loopFunc on

+


+

~turnOnLoopFunc = true

+


+


+

// turn goFunc off and again use loopFunc as goFunc

+


+

~turnOnGoFunc = false

+


+

~loopFuncAsGoFunc = true

+


+


+


+

// loop, again with loopFunc per item

+


+

~lookBack = 5

+


+


+

p.stop

+


+


+


+

Ex. 5:   PSloops controlling different sound params

+


+

// Overlapping of loops on different sound params can give interesting polyrhythmic structures

+


+

(

+

SynthDef(\psloop_1, { |out = 0, freq = 440, centDif = 5, rq = 0.1, cutoff = 1000, amp = 0.1

+

att = 0.01, sus = 0.0, rel = 0.01|

+

var sig = Saw.ar(freq * [1, (centDif * 0.01).midiratio], amp);

+

Out.ar(0, BPF.ar(sig, cutoff.clip(30, 8000)) * EnvGen.ar(Env.linen(att, sus, rel), doneAction: 2));

+

}, 0.01!6).add

+

)

+


+

(

+

// Function to generate a standard PSloop with lookBack arg to by controlled by env variable with suffix LB

+

// Pfunc could also be written as: PL((name ++ \LB).asSymbol)

+


+

~psLoop = { |src, name| PSloop(src, bufSize: 10, lookBack: Pfunc { currentEnvironment[(name ++ \LB).asSymbol] }) };

+


+

p = Pbind(

+

\instrument, \psloop_1,

+

\att, 0.01,

+

\amp, Pfunc { ~amp },

+

\sus, ~psLoop.(Prand([0.1, 0.2], inf), \sus),

+

\rel, ~psLoop.(Prand([0.01, 0.1, 1], inf), \rel),

+

\dur, ~psLoop.(Pn(Pshuf([1, 1, 2]/5)), \dur),

+

\centDif, Pshuf([5, -20, 40], inf),

+

\midinote, ~psLoop.(Pxrand((30..50), inf), \midinote),

+

\cutoff, ~psLoop.(Pshuf([500, 1500, 5000], inf), \cutoff)

+

);

+


+

q = Pbindf(p, \midinote, ~psLoop.(Pxrand((50..70), inf), \midinote));

+

r = Pbindf(p, \midinote, ~psLoop.(Pxrand((75..95), inf), \midinote));

+

  

+


+

// VarGui for control of lookBack params of 3 parallel streams

+

// zero values for args with suffix LB mean: no looping

+


+

// play loops by setting several params to non-zero values,

+

// you can grab params of different voices by using the alt key while

+

// moving a slider

+


+

VarGui({ |i| [

+

\susLB, [0, 7, \lin, 1, 0],

+

\relLB, [0, 7, \lin, 1, 0],

+

\durLB, [0, 7, \lin, 1, 0],

+

\midinoteLB, [0, 7, \lin, 1, 0],

+

\cutoffLB, [0, 7, \lin, 1, 0],

+

\amp, [0, 1, \lin, 0, 0.2 + (i * 0.1)]

+

] }!3, stream: [r, q, p], quant: 1/5

+

).gui(labelWidth: 80)

+

)

+


+


+


+


+ + diff --git a/Help/PSrecur.html b/Help/PSrecur.html new file mode 100755 index 0000000..dda8d99 --- /dev/null +++ b/Help/PSrecur.html @@ -0,0 +1,152 @@ + + + + + + + + + + + +

PSrecur Pattern to generate new values with a recursive Function 

+


+

Part of: miSCellaneous

+


+

Inherits from: PS / PStream

+


+

See also: MemoRoutine, PSx stream patterns, PS, PSdup, PSloop

+


+


+

Creation / Class Methods

+


+

*new (recurFunc, length, bufSize, start, copyItems, copySets)

+

+

Creates a new PSrecur object.

+

+

recurFunc - Recursive Function, the array of last values will be passed as first arg, count as second arg.

+

length - Number of output items, may be pattern or stream, defaults to inf.

+

bufSize - Size of buffer to store last values. 

+

If bufSize is not defined and start is not given or a single item, bufSize gets value 1.

+

If bufSize is not defined and start is an array bufSize gets its length.

+

start - Single start item or array ot items used for recursion.

+

copyItems - Determines if and how to copy items generated by recurFunc,

+

which are either non-Sets or member of Sets. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). 

+

Other values are interpreted as 0. Defaults to 0.

+

0: original item 

+

1: copy item

+

2: deepCopy item

+

copySets - Determines if and how to copy Sets, generated by recurFunc. 

+

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). 

+

Other values are interpreted as 0. Defaults to 1.

+

0: original Set 

+

1: copy Set

+

+

NOTE 1: The distinction of copying items and sets makes sense in the case of event streams.

+

Per default Events are copied (copySets == 1), not their values (copyItems == 0). 

+

By playing Events those are used to store additional data (synth ids, msgFuncs …) 

+

which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use 

+

MemoRoutine - copied Events will not contain this additional data. 

+

If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured 

+

then copying makes no sense, this is the normal case, so copyItems defaults to 0.

+

When going to alter the ouput, you might want to set copyItems to 1 for a PSx returning 

+

simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set

+

copySets to 1 and copyItems to 2 (an option copySets == 2 doesn't exist as

+

it would be contradictory in combination with copyItems < 2).

+


+

NOTE 2: Copy options concern copying into PSrecur's buffer as well as 

+

the output of a Stream derived from the PSrecur. When such a Stream is outputting copies 

+

this prevents unintended altering of items stored in the buffer of the source. On the other hand

+

storing copies in PSrecur's buffer prevents these from being altered unintendedly.

+


+


+

Instance Methods

+


+

recurFuncStream, recurFuncStream_(value)

+

+

Instance variable getter and setter methods. 

+


+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// another way to generate the fibonacci sequence

+

// the first arg passed to the Function is the PSrecur itself,

+

// x[0] refers to its last value, x[1] to the value before the last value 

+


+

(

+

a = PSrecur({ |x| x[0] + x[1] }, start: [0, 1]);

+

b = a.iter;

+

b.nextN(10);

+

)

+


+

// shorter with partial application

+


+

PSrecur(_[0]+_[1], start: [0, 1]).iter.nextN(10);

+


+


+


+

// recursion with event patterns

+

// function calculates an iterated average of past event values for all keys,

+

// events at the end of the array are taken into account most.  

+


+

(

+

u = { |e,f| e.copy.keysValuesChange { |k| e[k]+f[k]/2 } };

+

v = { |a| a.reduce(u) };

+

)

+


+

(

+

// three basic Events

+


+

e = (midinote: 65, dur: 0.75, amp: 0.1, pan: 0);

+

f = (midinote: 58, dur: 0.05, amp: 0.3, pan: -1);

+

g = (midinote: 92, dur: 0.05, amp: 0.4, pan: 1);

+


+

// mostly build "blurred" average of last five events, 

+

// by chance disturbance by choosing a basic event

+


+

p = PSrecur({ |x| 0.8.coin.if { v.(x[..4]) }{ [e,f,f,g].choose } }, start: [e,f,e,g,e]);

+


+

q = p.trace.play;

+

)

+


+

q.stop;

+


+


+


+ + diff --git a/Help/PSx stream patterns.html b/Help/PSx stream patterns.html new file mode 100755 index 0000000..21f6c0a --- /dev/null +++ b/Help/PSx stream patterns.html @@ -0,0 +1,100 @@ + + + + + + + + + + + +

PSx stream patterns Pattern variants that have a state and can remember their last values

+


+

Part of: miSCellaneous

+


+

See also: MemoRoutine, PS, PSdup, PSrecur, PSloop

+


+


+

In general Patterns are thought to have no state. They are defining models for the really generative objects, Streams, which respond to the method next that causes them to return a next value. So, in general, an arbitrary number of Streams might be derived from one Pattern, all behaving as defined by the latter.

+

However there are cases where it is comfortable to have objects that behave like Streams, e.g. resume from their last state if embedded, and at the same time still benefit from everything which is already implemented for Patterns. PSx stream patterns are an attempt to accomplish this. PSx patterns behave like Streams - they resume from last state when repeatedly embedded -, they remember their last value (or a number of last values) and they are real Patterns by subclassing, i.e. operators defined for Patterns can be applied. Internally they use Stream's subclass MemoRoutine which performs value buffering.

+


+


+

PSx value and event pattern classes

+


+

PS, PSdup, PSrecur, PSloop

+


+


+

Example

+


+

(

+

p = Pseq([ 

+

PS(Pseq((1..9), inf), 3), 

+

PS((Pseries() + 1) * 100, Pseq([1,2,3], inf)) 

+

], inf);

+


+

q = p.asStream; 

+


+

q.nextN(50);

+

)

+


+

// ATTENTION:

+


+

// It is important to remember that, differing from normal 

+

// Pattern convention, repeatedly applying .asStream to a 

+

// PSx pattern or a Pattern that encloses a PSx doesn't cause a Stream to begin at the start.

+

// Every new Stream refers to the internally used and previously left off MemoRoutine.

+


+


+

p.asStream.nextN(5);

+


+

p.asStream.nextN(10);

+


+


+

// For getting a totally new Stream you can reevaluate the Pattern definition or

+

// define the Pattern with a wrapping Function:

+


+


+

(

+

a = { 

+

Pseq([ 

+

PS(Pseq((1..9), inf), 3), 

+

PS((Pseries() + 1) * 100, Pseq([1,2,3], inf)) 

+

], inf); 

+

};

+


+

b = a.value.asStream; 

+


+

b.nextN(50);

+

)

+


+

a.value.asStream.nextN(5);

+


+

a.value.asStream.nextN(10);

+


+


+


+ + diff --git a/Help/PV_BinGap.html b/Help/PV_BinGap.html new file mode 100755 index 0000000..41d6f9b --- /dev/null +++ b/Help/PV_BinGap.html @@ -0,0 +1,140 @@ + + + + + + + + + + + +

PV_BinGap pseudo ugen keeping the complement of a spectral range

+


+

Part of: miSCellaneous

+


+

Inherits from: PV_ChainUGen

+


+

Based on PV_BrickWall, but instead of wipe parameters it takes two bin numbers.

+


+

See also: PV_BinRange, FFT Overview

+


+


+

Creation / Class Methods

+


+

*new (buffer, loBin, hiBin)

+

+

Creates a new PV_BinGap object.

+

+

buffer - FFT buffer.

+

loBin - low bin index of excluded range.

+

hiBin - high bin index of excluded range.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// frequencies are rounded to nearest bins

+


+

(

+

f = { |loFreq = 800, hiFreq = 1500, fundFreq = 50, amp = 0.1|

+

var bufSize = 1024, binRange, loBin, hiBin, sig, chain;

+


+

sig = Saw.ar(fundFreq, amp);

+


+

binRange = s.sampleRate / bufSize;

+

loBin = (loFreq / binRange).round;

+

hiBin = (hiFreq / binRange).round;

+


+

chain = FFT(LocalBuf(bufSize), sig);

+

chain = PV_BinGap(chain, loBin, hiBin);

+

IFFT(chain) ! 2;

+

};

+


+

x = f.play;

+


+

s.freqscope;

+

)

+


+

x.set(\loFreq, 300);

+


+

x.set(\hiFreq, 3000);

+


+

x.release;

+


+


+


+

// for multichannel expansion an array of mono buffers must be provided

+


+

(

+

g = { |loFreq = 800, hiFreq = #[1500, 1500] fundFreq = 50, amp = 0.1|

+

var bufSize = 1024, binRange, loBin, hiBin, sig, chain;

+


+

sig = Saw.ar(fundFreq, amp);

+


+

binRange = s.sampleRate / bufSize;

+

loBin = (loFreq / binRange).round;

+

hiBin = (hiFreq / binRange).round;

+


+

chain = FFT({ LocalBuf(bufSize) } ! 2, sig);

+

chain = PV_BinGap(chain, loBin, hiBin);

+

IFFT(chain);

+

};

+


+

x = g.play;

+


+

s.freqscope;

+

)

+


+

x.set(\loFreq, 300);

+


+

x.set(\hiFreq, [1200, 1200]);

+


+

x.set(\hiFreq, [800, 2000]);

+


+

x.set(\hiFreq, [2000, 800]);

+


+

x.release;

+


+


+


+


+ + diff --git a/Help/PV_BinRange.html b/Help/PV_BinRange.html new file mode 100755 index 0000000..6050d92 --- /dev/null +++ b/Help/PV_BinRange.html @@ -0,0 +1,141 @@ + + + + + + + + + + + +

PV_BinRange pseudo ugen keeping a spectral range

+


+

Part of: miSCellaneous

+


+

Inherits from: PV_ChainUGen

+


+

Based on PV_BrickWall, but instead of wipe parameters it takes two bin numbers.

+


+

See also: PV_BinGap, FFT Overview

+


+


+

Creation / Class Methods

+


+

*new (buffer, loBin, hiBin)

+

+

Creates a new PV_BinRange object.

+

+

buffer - FFT buffer.

+

loBin - low bin index of resulting range.

+

hiBin - high bin index of resulting range.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// frequencies are rounded to nearest bins

+


+

(

+

f = { |loFreq = 800, hiFreq = 1500, fundFreq = 50, amp = 0.1|

+

var bufSize = 1024, binRange, loBin, hiBin, sig, chain;

+


+

sig = Saw.ar(fundFreq, amp);

+


+

binRange = s.sampleRate / bufSize;

+

loBin = (loFreq / binRange).round;

+

hiBin = (hiFreq / binRange).round;

+


+

chain = FFT(LocalBuf(bufSize), sig);

+

chain = PV_BinRange(chain, loBin, hiBin);

+

IFFT(chain) ! 2;

+

};

+


+

x = f.play;

+


+

s.freqscope;

+

)

+


+

x.set(\loFreq, 300);

+


+

x.set(\hiFreq, 1000);

+


+

x.release;

+


+


+


+

// for multichannel expansion an array of mono buffers must be provided

+


+

(

+

g = { |loFreq = #[500, 500], hiFreq = 1500, fundFreq = 50, amp = 0.1|

+

var bufSize = 1024, binRange, loBin, hiBin, sig, chain;

+


+

sig = Saw.ar(fundFreq, amp);

+


+

binRange = s.sampleRate / bufSize;

+

loBin = (loFreq / binRange).round;

+

hiBin = (hiFreq / binRange).round;

+


+

chain = FFT({ LocalBuf(bufSize) } ! 2, sig);

+

chain = PV_BinRange(chain, loBin, hiBin);

+

IFFT(chain);

+

};

+


+

x = g.play;

+


+

s.freqscope;

+

)

+


+

x.set(\loFreq, [200, 200]);

+


+

x.set(\loFreq, [300, 1200]);

+


+

x.set(\loFreq, [1200, 300]);

+


+

x.set(\hiFreq, 2000);

+


+

x.release;

+


+


+


+


+ + diff --git a/Help/PbindFx.html b/Help/PbindFx.html new file mode 100755 index 0000000..23ee722 --- /dev/null +++ b/Help/PbindFx.html @@ -0,0 +1,2171 @@ + + + + + + + + + + + +

PbindFx event pattern for effect handling on per-event base 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pchain

+


+See also: Introduction to miSCellaneous
, Buffer Granulation, Live Granulation, kitchen studies, PmonoPar, PpolyPar, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

+


+


+

PbindFx works like a normal Pbind of event type 'note' in most regards, but with the additional option to define a number of effects. Their order and parameters can also be defined with patterns which allows a great flexibility: for each event an arbitrary multichannel effect graph can be applied, mixing sequential and parallel arrangement ad libitum. This requires a relatively high amount of resource management: bus allocation, routing and node ordering as well as delayed cleanup have to be done for each event. All necessary bookkeeping is done automatically, for some critical parameters though it's the user's responsibility to pass meaningful values (e.g. cleanupDelay for reverb has to be defined sufficiently high, otherwise reverb synth and audio bus might be freed before reverb has ended). There is always a tradeoff between flexibility and processing effort, if you won't change fx parameters on a per-event base or you won't reorder your effect arrangement, then you might prefer playing effects from and to predefined buses and control them otherwise, e.g. per LFOs (additionally possible also with PbindFx) or dedicated setting streams, see PmonoPar and PpolyPar. However with the strategy of effects bound to buses you have the same effect arrangements and parameters concerning all source signals sent to the same bus, more variation with such setups needs more (pre-)definition of buses, whereas with PbindFx overlapping events can be processed with different effect arrangements and parameters with no explicit effort.  

+

One possible application of PbindFx is applying effects per grain, for the project kitchen studies I documented the source code of a fixed media piece in six parts, using this technique.

+


+

WARNING:

+

As bus allocation is done dynamically per event, there is a circumvented, but still potential danger of creating feedback loops. To prevent this, additional "zero synths" are started with bus-reading fx synths, playing a zero signal with ReplaceOut to the buses in question, they are placed before those fx / source synth(s), which will play there too. For all test examples, even with deliberately bad values, zero synths turned out to be an effective way to block unwanted input signals and feedback, as they last as long as fx / source synths (they even overlap them a bit). However, with extraordinary parameter values for timing, improperly defined fx / source synths, sloppy audio bus mapping and / or parallel actions that affect resource management globally, feedback, as in any situation of heavy bus repatching, can not be totally excluded. Be aware of that, avoid high levels and be careful with headphones !

+


+


+


+

Creation / Class Methods

+


+

*new (pbindData ... fxData)

+

+

Creates a new PbindFx object.

+

+

pbindData - SequenceableCollection of Pbind's key/value pairs or event pattern.

+

Passing a list saves explicitely typing Pbind, but passing an event pattern is more flexible,

+

as it allows replacement (Ex.7), event pattern filtering (Ex.3a) and similar operations.

+


+

specific keys:

+

+

\fxOrder - For each event it can be given in three ways, for single effects and

+

sequential ordering it may be 

+

(a) an Integer, or 

+

(b) a SequenceableCollection of Integers, 

+

indicating the effect order. Effect counting starts with 1, 0 means no effect (default).

+

E.g. if three effects are passed to fxData, [1], [2], [3], [1, 2], [1, 3], [2, 3], 

+

[2, 1], [3, 1], [3, 2], [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1],

+

would represent all possible effect orders with each effect applied once. 

+

Passing single Integers is equivalent to passing them in an array.

+

Data concerning one event can also be given as

+

(c) a Ref object containing an IdentityDictionary, representing the effect graph. 

+

Keys of the dictionary – single Integers – are identified with effects of fxData, values

+

of the dictionary might be single Integers or SequenceableCollections of

+

Integers, indicating a branching of effects (whenever you want a branching of effects

+

or routing two different effects to a third one, the input must be given as a ref'd IdentityDictionary).

+

Within the effect graph an explicit direct out can be denoted with the Symbol \o,

+

0 represents the source. The graph must be acyclic, a check is performed.

+

fxOrder can also be a Pattern, sequencing effect orders of the forms (a) - (c).

+

See principles of operation below and examples 10 (a)-(c).

+

+

\cleanupDelay - Number or Pattern to generate Numbers, taken as seconds.

+

Its meaning differs, depending if source synth (passed by \instrument) has

+

a gated or fixed length envelope. If a gate control is encountered in the SynthDef

+

description, a gated envelope is assumed.

+

In the latter case this arg determines the earliest time after release when

+

cleanup may start. With a fixed-length envelope it determines the earliest time 

+

after synth start when cleanup may start.

+

With effects defined, cleanupDelays of source and effects are summarized.

+

Defaults to the class variable defaultSourceCleanupDelay which defaults to 0.3.

+

Typically you would take the releaseTime of the source synth's / synthdef's 

+

gated envelope, or the maximum overall length of the fixed-length envelope,

+

each plus a small delta.

+

+

\cleanupClock - The clock on which freeing of audio buses is scheduled with SkipJack objects.

+

As the clock should survive CmdPeriod its permanent flag must be set to true.

+

Per default the SystemClock is used, but for certain cases, e.g. granulation 

+

you might want to pass a TempoClock with higher queueSize, see examples below.

+

+

\cleanupDt - Number or Pattern to generate Numbers, taken as seconds.

+

Determines the delta time for cleanup with SkipJack objects. In those intervals 

+

it is checked whether event-specific cleanup delaytimes have been reached 

+

and cleanup (freeing buses) should be performed. Defaults to the class variable 

+

defaultCleanupDt which defaults to 0.2. With higher values more SkipJack objects

+

have to be scheduled at the same time, although with fewer activity.

+

+

\freePerGroup - Boolean, defaults to false.

+

Determines if effects and zero synths of the chain should be freed separately or

+

removed at the end of the chain by freeing the enclosing group.

+

With more effects and longer cleanupDelays the latter leads to a larger number

+

of parallel synths and might be wasteful thus. On the other hand it can be 

+

a useful option with short events and cleanupDelays, e.g. in case of granulation. 

+

See below timing scheme for a more detailled description.

+


+

\otherBusArgs - Takes SequenceableCollection of Symbols, defaults to nil.

+

For all passed symbols the source synth is enabled to read from and write to external buses,

+

which are passed to an arg of that name, LocalIn and LocalOut are allowed anyway.

+

Per default a restrictive check of synth I/O ugens and matching is performed in order to prevent

+

unintended reading from resp. writing to buses. With this option you can allow reading

+

and writing in a controlled way, see Ex. 6a and 6b.

+


+

+

fxData - SequenceableCollection(s) of key/value pairs defining effect sequencing or event pattern.

+

Passing a list saves explicitely typing Pbind, but passing an event pattern is more flexible,

+

as it allows replacement (Ex.7), event pattern filtering (Ex.3a) and similar operations.

+


+

specific keys:

+


+

\fx - Symbol or Pattern to generate Symbols.

+

Determines the effect synthdef.

+


+

\cleanupDelay - Number or Pattern to generate Numbers, taken as seconds.

+

Determines the earliest time after effect node delay when cleanup, 

+

including freeing the effect synth, may start.

+

With effects defined, cleanupDelays of source and effects are summarized.

+

Defaults to the class variable defaultFxCleanupDelay which defaults to 0.05.

+

Typically you would take the maximum delay of the effect synth plus a small delta. 

+

+

\otherBusArgs - Takes SequenceableCollection of Symbols, defaults to nil.

+

For all passed symbols the fx synth is enabled to read from and write to external buses,

+

which are passed to an arg of that name, LocalIn and LocalOut are allowed anyway.

+

Per default a restrictive check of synth I/O ugens and matching is performed in order to prevent

+

unintended reading from resp. writing to buses. With this option you can allow reading

+

in a controlled way, see Ex. 6a and 6b.

+


+


+

*defaultSourceCleanupDelay 

+

+

Get the value of this class variable. Defaults to 0.3.

+


+

*defaultSourceCleanupDelay_(value)

+

+

Set this class variable to value.

+


+

*defaultCleanupDt 

+

+

Get the value of this class variable. Defaults to 0.2.

+


+

*defaultCleanupDt_(value)

+

+

Set this class variable to value. 

+


+

*defaultFxCleanupDelay 

+

+

Get the value of this class variable. Defaults to 0.05.

+


+

*defaultFxCleanupDelay_(value)

+

+

Set this class variable to value. 

+


+


+


+


+

Principle of operation

+


+

Per-event effect routing with PbindFx, example scheme of two effects applied sequentially:

+


+

This can typically be achieved by passing an array [i, j] to \fxOrder, where i and j denote

+

arbitrary unequal positive effect numbers (numbers smaller or equal than the size of fxData).

+

+

+


+

Effects FX#1 and FX#2 read from buses BUS#1 and BUS#2 which are reserved for the duration 

+

of the event plus a cleanup time. BUS#1 and BUS#2 get their data from source synth SRC resp. FX#1. 

+

"Zero synths" Z#1 and Z#2 are placed before them in node order, they are lasting as long as 

+

(in fact a bit longer than) FX#1 and FX#2, playing zero signals to BUS#1 and BUS#2 with ReplaceOut and 

+

cancelling out possible residual signals on those buses, thus blocking feedback. 

+

BUS#1 and BUS#2 might be multichannel buses, in that case a number of mono zero synths 

+

is established for each Z#i. 

+

Two dedicated groups are generated for each event: FXGRP is the container for all

+

event-generated synths and SRCGRP is placed at its head. Z#1 is placed at the head of

+

SRCGRP, other zero synths and effects are sequentially placed upwards from the tail

+

of FXGRP, interlaced in the way described below.

+

Finally source synth(s) are placed at tail of SRCGRP (the group passed further to the note event).

+


+


+

node ordering for n = 2

+


+

FXGRP:

+

SRCGRP:

+

Z#1

+

SRC

+

Z#2 

+

FX#1

+

FX#2

+


+


+

You can also pass a group (or a pattern of groups) to PbindFx, in that case

+

FXGRP is related to the group depending on \addAction (default \addToHead):

+


+


+

general node ordering with n sequentially applied effects for n > 2 

+

group GRP passed to PbindFx with key \group, 

+

default addAction \addToHead

+


+

GRP:

+

  FXGRP:

+

SRCGRP:

+

Z#1

+

SRC

+

Z#2 

+

FX#1

+

...

+

...

+

Z#n

+

FX#n-1

+

FX#n

+


+


+

Note that effect order is arbitrary per event, determined by key \fxOrder, 

+

in these examples FX#i denote the order in the regarded event, 

+

not the order in which the effects are passed to PbindFx.

+

The whole process is implemented via dedicated event type 'pbindFx', 

+

an extension of event type 'note', which is chosen with PbindFx by default.

+

The following schemes refer to server-side timing, additional lang-side offset might be passed with 

+

lag (in seconds) to ensure proper timing for sequences combining delayed and non-delayed effects 

+

e.g. including occasional echo as in several of the examples below.

+


+


+

Timing scheme of PbindFx with two effects applied sequentially, 

+

source synth with gated envelope:

+


+


+

+

+

+

t#0: start SRC, Z#i, FX#i and groups with server-side ordering as described in routing scheme,

+

in fact Z#i are started slightly earlier.

+

t#1: begin of SRC envelope release period, caused by a release message (set gate arg to 0)

+

t#2: end of SRC envelope release period, probably end of source synth (doneAction = 2)

+

t#3: supposed latest end of source synth due to given cleanupDelay of source, added to t#1

+

(cleanupDelay might be passed as a constant maximum release time for all events)

+

t#4: with ~freePerGroup == false (default): freeing of FX#1 and Z#1, the latter a bit later.

+

with ~freePerGroup == true: do nothing

+

t#5: free FXGRP, thus also FX#2 and Z#2.

+


+

For longer effect chains with n effects the case distinction of t#4 applies to all pairs Z#i / FX#i for 1 < i < n:

+

with ~freePerGroup == true they all are freed at last by freeing the group.

+


+


+

Timing scheme of PbindFx with two effects applied sequentially, 

+

source synth with fixed-length envelope:

+


+


+

+

+


+

t#0: start SRC, Z#i, FX#i and groups with server-side ordering as described in routing scheme,

+

in fact Z#i are started slightly earlier.

+

t#1: begin of SRC envelope release period, caused by the synth itself (no setting gate to 0)

+

t#2: end of SRC envelope release period, probably end of source synth (doneAction = 2)

+

t#3: supposed latest end of source synth due to given cleanupDelay of source, added to t#0

+

(cleanupDelay might be passed as a constant maximum envelope length for all events)

+

t#4 - t#5: as with gated envelope

+


+


+

Parallel effect processing, arbitrary effect graphs:

+


+

The most simple case of applying two effects in parallel can be triggered by passing `(0: [1, 2]) to fxOrder.

+

Effect numbers occurring in arrays of dictionary values cause a routing from these effects to out.

+

Symbol \o (for destination out) can also be passed explicitely.

+


+

Branching like this requires the use of a split synth which routes the output to the demanded

+

multitude of fx buses. A suitable predefined split synthdef is chosen according to the number of branches

+

and the channel number of the signal to be splitted – currently both is limited by 8, however

+

synths, which are only playing to out directly, might have an arbitrary number of output channels.

+


+

Different to sequential fx processing, both fx bus zero synths have to be added before the source,

+

additional zero synth(s) for the split bus are prepended.

+


+


+


+

+


+

The following effect graph can be established by fxOrder `(0: [1, 2, 3], 2: [4, \o], 3: 2),

+

split synths, zero synths (for fx buses and split buses) are omitted in this scheme.

+

For each (acyclic) fx graph a topological order is calculated (here it could e.g. be [0,1,3,2,4])

+

and the node ordering, including FXGRP and SRCGRP, similar to the sequential case, 

+

is derived accordingly. Some small differences, especially concerning the cleanup delay times, 

+

have to be taken into account, these details are omitted here.

+


+

+

+


+

Conventions 

+


+

1.) Source instrument and effect SynthDefs must be known to SynthDescLib.global 

+

(e.g. by creating SynthDefs with methods 'add' or 'store')

+


+

2.) Fx SynthDefs must be defined with arg 'out' for the outbus index, arg 'in' for inbus index

+

and use In.ar(in, ...) within the SynthDef.

+

It's up to the user whether to define the effect with dry/wet mix option.

+

Effect synths don't need to have an envelope, their freeing is handled by the event type function.

+

+

3.) Effect chains must be defined properly in terms of in/out channel number.

+

For each event the bus matching of the effect chain is checked, following these conventions:

+

+

.) For source and fx SynthDefs there must be only one out ugen using 'out' as bus arg,

+

LocalOut is allowed, other out ugens can be admitted by \otherBusArgs.

+

.) Source SynthDefs must not have in ugens, except LocalIn or they are admitted by \otherBusArgs. 

+

.) Fxs must read from buses with ugen In.ar(in, ...) refering to the bus arg 'in', 

+

there must not be other in ugens within the fx SynthDef except LocalIn or 

+

they are admitted by \otherBusArgs, see Exs. 6a and 6b.

+

.) Number of out channels of preceeding source / fx synth must not be greater than 

+

the number of the following fx synth's in channels, this is checked for all pairs of an fx graph.

+

.) Mismatches of above points lead to errors.

+

+

4.) Checks of (3) are also based on info in SynthDescLib.global. It is possible to replace SynthDefs 

+

on the fly (Ex. 7a, 7b), in that case I'd recommend to use also methods 'add' or 'store' – 

+

e.g. in case of using 'send' for redefinition no bus matching check is performed and 

+

a possibly wrong routing would be undetected.

+

+

5.) As shown in above graphics the source synth's cleanupDelay is interpretated differentely 

+

with gated and non-gated (fixed-length) envelopes. This is done automatically by looking 

+

for a 'gate' arg in the SynthDef's SynthDesc. It's the users responsibility to use the 

+

conventional arg 'gate' for release in the SynthDef and omit a 'gate' arg with 

+

SynthDefs employing fixed-length envelopes.

+


+

6.) As with normal event patterns the source Pbind / Pbind pairs may be defined with arrays 

+

to produce multiple synths per event, then the whole source signal is routed to the fx graph 

+

(see Ex. 2b, 2c and others). fxData pairs can also be defined with arrays, which causes 

+

parallel processing per node ("implicit parallelism"), see Ex. 4a.

+

For applying different fxs to parallel events (resp. chords) use parallel PbindFxs (Exs. 3a, 3b). 

+

It is of course also possible that fx synths have array args and fx patterns are passing them 

+

with the double-bracketing convention used for these cases (see Event patterns and array args).

+

+

7.) Source instrument and effect SynthDefs are allowed to have args of same name. 

+

There is no problem as key/value pairs are stored in separate lists/events.

+

 

+

8.) PbindFx is implemented per automatically chosen effect type 'pbindFx', which employs 

+

event type 'note', thus an event type must neither be passed to pbindData nor to fxData.

+

+

9.) The value conversion framework can be used for fxData, e.g. by passing \midinote instead of

+

\freq or \db instead of \amp as with Pbind, see Ex.9. Other than with Pbind, freq and amp event defaults 

+

are not passed to fx synths, if no such values are passed via fxData. 

+

In that case default values of fx synths are taken.

+

+

10.) While playing PbindFx you should not play with allocation affecting private buses.

+

Freeing buses is done by SkipJack objects, so you should not forcefully stop 

+

all SkipJack objects while playing PbindFx.

+


+

11.) Keys \group and \addAction may be passed, they determine how the group enclosing 

+

event-generated synths is related to the passed group, see scheme 'Principles of operation'.

+

+

12.) Zero synths are using the SynthDefs 'pbindFx_zero' and 'pbindFx_splitZero' which 

+

are written to disk at startup time, as well as split synths pbindFx_split_axb for a = 2,...,8

+

and b = 1,...,8. Of course these SynthDefs shouldn't be deleted or exchanged.

+

+


+

Resources, troubleshooting

+


+

1.) You might encounter the error message "Meta_Bus:audio: failed to get an audio bus allocated." 

+

As audio buses for effect chains are allocated and freed per event a higher number of 

+

private audio buses is likely to be required (more than default 128). 

+

You might also encounter the error message "exception in real time: alloc failed, 

+

increase server's memory allocation (e.g. via ServerOptions)".

+

Hence it's recommended to set the concerned server options before (re-)booting and working with PbindFx, e.g.:

+

+

(

+

s.options.numPrivateAudioBusChannels = 1024;

+

s.options.memSize = 8192 * 16;

+

s.reboot;

+

)

+


+

2.) You might encounter the warning "Scheduler queue is full."

+

Per default delayed freeing of buses is scheduled on SystemClock, which defaults to queueSize 1024.

+

In case of granulation and/or large cleanup delays it's recommended to pass a cleanup clock with

+

sufficiently large queueSize via pbindData, its permanent flag must be set to true, e.g.:

+

+

...

+

\cleanupClock, t = TempoClock(queueSize: 8192).permanent_(true) 

+

...

+

+

Note that this clock keeps on running and survives CmdPeriod, you should explicitely stop it

+

if you don't need it anymore, hence it should be stored in a variable. In case you haven't done that

+

you can still stop all TempoClocks and remove them from CmdPeriod with

+

+

TempoClock.all.copy.do(_.stop)

+

+

3.) Cleanup delays for source and effects (or, if not passed, their default values) should be sufficiently large

+

(see description of \cleanupDelay), otherwise effects and audio buses might be freed too early

+

and signals cut.

+


+

4.) Some effects, like echo, introduce a delay. If sequencing mixes delayed events

+

with non-delayed events, entries of the latter have to be delayed accordingly to preserve correct timing, 

+

this can be done by setting an offset in seconds with \lag. See examples with echo below.

+


+


+


+

Example 1: Straight usage with unchanged effect order

+


+

Example 1a: Source synth with sustained envelope

+


+


+

// boot server with extended resources

+


+

(

+

s.options.numPrivateAudioBusChannels = 1024;

+

s.options.memSize = 8192 * 16;

+

s.reboot;

+

)

+


+

// basic source and effect synthdefs for this help file

+


+

(

+

// All ins and outs use two channels

+


+

// source synthdef

+

// take releaseTime = decayTime

+


+

SynthDef(\source, { |out = 0, freq = 400, decayTime = 0.5,

+

attackTime = 0.005, amp = 0.1, gate = 1|

+

var env, sig = Decay.ar(Impulse.ar(0), decayTime, Saw.ar(freq));

+

env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2);

+

Out.ar(out, sig ! 2 * env)

+

}).add;

+


+


+

// spat fx

+

// This effect introduces a very small delay,

+

// in examples balancing by lag (as it obviously has to be done with echo) is neglected.

+


+

SynthDef(\spat, { |out, in, freq = 1, maxDelayTime = 0.005,

+

amp = 1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = DelayC.ar(

+

inSig,

+

maxDelayTime,

+

{ LFDNoise3.ar(freq, maxDelayTime, maxDelayTime/2) } ! 2,

+

amp

+

);

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+


+

// echo fx, always unified delay maxEchoDelta

+


+

SynthDef(\echo, { |out, in, maxEchoDelta = 0.2, echoDelta = 0.1,

+

decayTime = 1, amp = 1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = DelayL.ar( 

+

CombL.ar(inSig, maxEchoDelta, echoDelta, decayTime, amp), 

+

maxEchoDelta, 

+

maxEchoDelta - echoDelta

+

);

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+


+

// wah-wah fx

+


+

SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000,

+

cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = RLPF.ar(

+

inSig,

+

LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi),

+

rq,

+

amp

+

).softclip;

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+


+

// reverb fx

+

// rough estimation: freeVerb's room arg = decayTime / 10

+


+

SynthDef(\reverb, { |out, in, damp = 0.5,

+

decayTime = 10, amp = 1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

Out.ar(out, FreeVerb.ar(inSig, mix, min(decayTime, 10) / 10, damp, amp));

+

}).add;

+

)

+


+


+

// Fx params are sequenced on a per-event base.

+


+

// see server window: number of groups (divided by 2) indicates 

+

// the number of parallel event chains in action

+

// check while running with s.queryAllNodes

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.25,

+

\amp, 0.2,

+

\midinote, Prand([

+

Pwhite(80, 90, 1),

+

Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf),

+

], inf),

+


+

\fxOrder, [1, 2], 

+

// With a sustained envelope \cleanupDelay refers to the maximum release time,

+

// in SynthDef \source releaseTime = decayTime, so take cleanupDelay = decayTime

+

\decayTime, Pwhite(0.2, 2),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

// oscillation of delay -> frequency modulation of source signal

+

\freq, Prand([1, 2, 3], inf),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

// variation by sequencing of params

+

\fx, \wah,

+

\mix, Pseq([0.2, 0.5, 0.7], inf),

+

\cutOffMoveFreq, Pseq([1, 2, 5, 10], inf),

+

\cleanupDelay, 0.01

+

]

+

);

+


+

q = p.play;

+

)

+


+

// see server window and compare "regular" stop 

+

// (descending number of groups, synths and ugens reflects delayed cleanup)

+

// with stopping the same example by Cmd-Period

+


+

q.stop;

+


+


+

Example 1b: Source synth with fixed-length envelope

+


+

// SynthDefs from Ex. 1a plus

+

// SynthDef variation with adsr args

+


+

(

+

SynthDef(\source_adsrFixed, { |out = 0, freq = 400, decayTime = 0.5, 

+

att = 0.005, dec = 0.01, sus = 0.2, rel = 0.3, susLevel = 0.5, amp = 0.1|

+

var env, sig = Saw.ar(freq);

+

env = EnvGen.kr(Env([0, 1, susLevel, susLevel, 0], [att, dec, sus, rel]), doneAction: 2);

+

Out.ar(out, sig ! 2 * env * amp)

+

}).add;

+

)

+


+

// adsr values passed, \cleanupDelay estimated as max of sum

+


+

(

+

p = PbindFx([

+

\instrument, \source_adsrFixed,

+

\dur, 0.25,

+

\att, Pwhite(0.005, 0.01),

+

\dec, Pwhite(0.01, 0.02),

+

\sus, Pwhite(0.02, 0.3),

+

\rel, Pwhite(0.2, 1.5),

+


+

\susLevel, 0.4,

+

\amp, 0.2,

+


+

\midinote, Prand([

+

Pwhite(80, 90, 1),

+

Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf),

+

], inf),

+


+

\fxOrder, [1, 2], 

+

+

// cleanupDelay must be larger than max env length, otherwise events might be cut !

+

// here we do an estimation (att + dec + sus + rel < 2),

+

// but it could be summed from those event values too, e.g. with

+

// \cleanupDelay, Pfunc { |e| e.att + e.dec + e.sus + e.rel }

+

\cleanupDelay, 2

+

],[

+

\fx, \spat,

+

\freq, Prand([1, 2, 3], inf),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \wah,

+

\mix, Pseq([0.2, 0.5, 0.7], inf),

+

\cutOffMoveFreq, Pseq([1, 2, 5, 10], inf),

+

\cleanupDelay, 0.01

+

]

+

);

+


+

q = p.play;

+

)

+


+


+

// check node order while running

+


+

s.queryAllNodes;

+


+

q.stop;

+


+


+

Example 2: Sequencing of different effect chains

+


+

Example 2a: Determined fx sequence

+


+

// PbindFx using spat and echo effects.

+

// Especially relevant keys here are \fxOrder which determines fx sequencing

+

// and \cleanupDelay for proper releaseTimes of source and effects

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.5,

+

\amp, 0.3,

+

\midinote, Pwhite(50, 90),

+


+

// fx sequence \spat, \spat + \echo, etc.

+

\fxOrder, Pseq([1, [1,2]], inf),

+


+

// echo is delayed (maxEchoDelta = 0.2),

+

// compensate here by shift when no echo

+

// we need \lag rather than \timingOffset as the whole delaytime calculation refers to seconds

+

\lag, Pseq([0.2, 0], inf),

+


+

// in SynthDef \source releaseTime = decayTime, so take cleanupDelay = decayTime

+

\decayTime, Pseq([1, 0.1], inf),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

// define effect with index 1

+

\fx, \spat,

+

\maxDelayTime, 0.005,

+


+

// oscillation of delay -> frequence modulation of source signal

+

\freq, Pseq([1, 1, 10], inf),

+


+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

// define effect with index 2

+

\fx, \echo,

+

\echoDelta, 0.08,

+

\decayTime, Pwhite(0.8, 3),

+


+

\cleanupDelay, Pkey(\decayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 2b: Random fx sequence

+


+

// If more than one synth per event is produced (here by key 'midinote'), 

+

// the effect chain is applied to all of them, see Ex. 3 for applying 

+

// different effects to parallel synths.

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.2,

+

\amp, 0.3,

+


+

// downwards tendency + chord sequence

+

\midinote, Pseq((90, 80..50), inf) +

+

Pn(Pshuf([[0, 5], 0, [0, 2.5], [-2.5, 12.5], [-3, 0]])),

+


+

\fxOrder, Prand([1, [1,2], [1,2]], inf),

+


+

// lag must be adapted to maxEchoDelta

+

\lag, Pfunc { |e| e.fxOrder.isArray.if { 0 }{ 0.2 } },

+


+

// echo -> shorter source decay

+

\decayTime, Pfunc { |e| e.fxOrder.isArray.if { 0.1 }{ 0.7 } },

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, Pseq((1..5)/50, inf),

+

\decayTime, 1,

+

\cleanupDelay, Pkey(\decayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 2c: Some extensions

+


+

// Additional use of rests, reverb added.

+

// Here the reverb usage is deliberately wasteful, see Ex.2d for an alternative.

+

// The use of Pn + Pshuf (or equivalently Pshufn) gives 

+

// balanced random variation for several key streams

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, Pn(Pshuf(0.2!5 ++ Rest(0.2))),

+


+

\midinote, Pseq((90, 80..40), inf) +

+

Pn(Pshuf([[0, 5], 0, [0, 2.5], [-2.5, 12.5], [-3, 0]])),

+


+

\fxOrder, Pn(Pshuf([[1,2], [1,2,3], [3,1], 1])),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, Pfunc { |e| (e.fxOrder != [1,2]).if { 0.3 }{ 0.6 } },

+


+

\decayTime, Pfunc { |e| 

+

rrand(0.3, 0.8) / (e.fxOrder.asArray.includes(2).if { 10 }{ 1 }) 

+

},

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, Pn(Pshuf([1, 1, 1, 5, 20, 50])),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, Pseq((1..5)/50, inf),

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \reverb,

+

\mix, 0.3,

+

\damp, 0.1,

+

\decayTime, Pwhite(3.0, 10),

+

\cleanupDelay, Pkey(\decayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 2d: Saving resources 

+


+

// If effects have a long cleanup delay, you will get a possibly large number of

+

// overlapping effect chains. E.g. in Ex. 2c many reverb synths can be there in

+

// parallel, the decayTime is controlled by Pwhite(3.0, 10), so it might well be

+

// that reverbs with decayTimes 7.95, 8, and 8.1 are instantiated in parallel,

+

// which doesn't make much difference and is quite wasteful.

+

// Reverb is often placed at the last position of the effect chain,

+

// so a more efficient approach would be the following: do

+

// all effect sequencing without reverb with PbindFx and pipe

+

// the overall out to a permanently running reverb.

+


+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

// start two reverbs with different parameters, read from dedicated buses

+


+

(

+

a = Bus.audio(s, 2);

+

b = Bus.audio(s, 2);

+


+

x = Synth(\reverb, [mix: 0.3, damp: 0.1, decayTime: 3, in: a]);

+

y = Synth(\reverb, [mix: 0.2, damp: 0.1, decayTime: 10, in: b]);

+

)

+

  

+

// play PbindFx 

+

// compare CPU usage with Ex.2c

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, Pn(Pshuf(0.2!5 ++ Rest(0.2))),

+


+

\midinote, Pseq((90, 80..40), inf) +

+

Pn(Pshuf([[0, 5], 0, [0, 2.5], 0, [-2.5, 12.5], [-3, 0]])),

+


+

\fxOrder, Pn(Pshuf([1, 2, [1,2]])),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, Pfunc { |e| (e.fxOrder != [1,2]).if { 0.3 }{ 0.6 } },

+


+

\decayTime, Pfunc { |e| 

+

rrand(0.3, 0.8) / (e.fxOrder.asArray.includes(2).if { 10 }{ 1 }) 

+

},

+

\cleanupDelay, Pkey(\decayTime),

+


+

// pipe out to different reverbs resp. 0 (no reverb)

+

\out, Pn(Pshuf([0, 0, a, a, b]))

+

],[

+

\fx, \spat,

+

\freq, Pn(Pshuf([1, 1, 1, 5, 20, 50])),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, Pseq((1..5)/50, inf),

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+

// stop

+


+

q.stop;

+


+

// free extra resources

+


+

[x, y, a, b].do(_.free);

+


+


+


+

Example 3: Different effects for parallel synths

+


+

// This can be done with parallel PbindFxs

+


+

Example 3a: Using a template Pbind

+


+

// Here the option of passing a source Pbind instead of a list of Pbind pairs can be used.

+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// master pattern, fxOrders defines fxOrder for voices of chord

+

f = Pbind(

+

\dur, 0.3,

+

\type, \rest,

+

\fxOrders, Pn(Pshuf([

+

[[1, 3], 2, 1], [1, [1, 3], 2], [2, 1, [1, 3]],

+

[0, 1, 1], [1, 0, 1], [1, 1, 0]

+

]).collect { |o| ~o = o })

+

);

+


+

// core source Pbind

+

a = Pbind(

+

\instrument, \source,

+

\dur, 0.3,

+


+

// reference to fxOrder will be got from Pchains below

+

\lag, Pfunc { |e| e.fxOrder.includes(2).if { 0 }{ 0.2 } },

+

\amp, Pfunc { |e| e.fxOrder.any([2,3].includes(_)).if { 0.3 }{ 0.1 } },

+


+

\decayTime, Pfunc { |e| rrand(0.5, 0.7) / (e.fxOrder.includes(2).if { 10 }{ 1 }) },

+

\cleanupDelay, Pkey(\decayTime)

+

);

+


+

// lists of fx pairs

+

b = [[

+

\fx, \spat,

+

\freq, Pn(Pshuf([1, 2, 3, 10])),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, 3/50,

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \wah,

+

\mix, 0.5,

+

\cutOffMoveFreq, Pseq([5, 10], inf),

+

\cleanupDelay, 0.01

+

]];

+


+

// derive three Pchains from core Pbind, 

+

// voice-specific fxOrder will be read from master pattern

+

u = a <> Pbind(

+

\fxOrder, Pfunc { ~o[0].asArray },

+

\midinote, 72

+

);

+


+

v = a <> Pbind(

+

\fxOrder, Pfunc { ~o[1].asArray },

+

\midinote, Pstutter(Pwhite(5, 10), Prand((60..70), inf))

+

);

+


+

w = a <> Pbind(

+

\fxOrder, Pfunc { ~o[2].asArray },

+

\midinote, Pstutter(Pwhite(5, 10), Prand((75..85), inf))

+

);

+


+


+

// play in parallel, master must be before

+


+

d = 0.001;

+


+

q = Ptpar([

+

0, f,

+

d, PbindFx(u, *b),

+

d, PbindFx(v, *b),

+

d, PbindFx(w, *b)

+

]).play;

+

)

+


+

q.stop;

+


+


+


+

Example 3b: Using a PbindFx generator Function

+


+

// Equivalent to Ex. 3a, but might look more straight, as 

+

// fxOrder pair already generated with PbindFx Function.

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// master pattern for fxOrder

+

f = Pbind(

+

\dur, 0.3,

+

\type, \rest,

+

\fxOrders, Pn(Pshuf([

+

[[1, 3], 2, 1], [1, [1, 3], 2], [2, 1, [1, 3]],

+

[0, 1, 1], [1, 0, 1], [1, 1, 0]

+

]).collect { |o| ~o = o })

+

);

+


+

// PbindFx generator

+


+

g = { |i| PbindFx([

+

\instrument, \source,

+

\dur, 0.3,

+


+

\fxOrder, Pfunc { ~o[i].asArray },

+

\lag, Pfunc { |e| e.fxOrder.includes(2).if { 0 }{ 0.2 } },

+

\amp, Pfunc { |e| e.fxOrder.any([2,3].includes(_)).if { 0.3 }{ 0.1 } },

+


+

\decayTime, Pfunc { |e| rrand(0.5, 0.7) / (e.fxOrder.includes(2).if { 10 }{ 1 }) },

+

\cleanupDelay, Pkey(\decayTime),

+

],[

+

\fx, \spat,

+

\freq, Pn(Pshuf([1, 2, 3, 10])),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, 3/50,

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \wah,

+

\mix, 0.5,

+

\cutOffMoveFreq, Pseq([5, 10], inf),

+

\cleanupDelay, 0.01

+

]

+

);

+

};

+


+

// derive three Pbindfs from PbindFx generator,

+

// as PbindFx is a subclass of Pbind, you can apply Pbindf as to Pbind

+


+

u = Pbindf(g.(0), \midinote, 72);

+

v = Pbindf(g.(1), \midinote, Pstutter(Pwhite(5, 10), Prand((60..70), inf)));

+

w = Pbindf(g.(2), \midinote, Pstutter(Pwhite(5, 10), Prand((75..85), inf)));

+


+

d = 0.001;

+

q = Ptpar([0, f, d, u, d, v, d, w]).play;

+

)

+


+

q.stop;

+


+


+


+

Example 4: Applying the same fx SynthDef more than once in a chain

+


+


+

Example 4a: Implicit duplication (= implicit parallelism)

+


+

// Within a graph node parallelism can be established in analogy to 

+

// the generation of multiple synths with Pbind: 

+

// by passing an array as value within fxData.

+


+

(

+

// pitchshift fx, result can easily be controlled by ear

+


+

SynthDef(\pitchShift, { |out, in, windowSize = 0.2, midiShift = 1,

+

    pitchDispersion = 0, timeDispersion = 0, amp = 1, mix = 1|

+

    var sig, inSig = In.ar(in, 2);

+


+

sig = PitchShift.ar(

+

inSig,

+

windowSize,

+

midiShift.midiratio,

+

pitchDispersion,

+

timeDispersion

+

);

+


+

    Out.ar(out, (1 - mix) * inSig + (sig * mix) * amp);

+

}).add;

+


+


+


+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.5,

+

\amp, 0.2,

+

\midinote, Pwhite(50, 80),

+


+

\fxOrder, 1,

+

        // With a sustained envelope \cleanupDelay refers to the maximum release time,

+

        // in SynthDef \source releaseTime = decayTime, so take cleanupDelay = decayTime

+

\decayTime, 1.5,

+

\cleanupDelay, Pkey(\decayTime)

+

    ],[

+

        // variation by sequencing of params

+

\fx, \pitchShift,

+

\mix, 0.8,

+

// implicitely generate parallel processing with different fx params

+

// the two fxs applied in parallel together with the source result in a sequence of major triads

+

\midiShift, [4, 7],

+

\windowSize, 0.04,

+

\timeDispersion, 0.005,

+

\cleanupDelay, 0.01

+

    ]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 4b: Explicit duplication

+


+

// By passing the same fx in different fxData args you have all options

+

// by defining the fx graph: in sequence, in parallel or however.

+

// Here is an example for explicit duplication in sequence,

+

// for defining explicit parallelism and arbitrary fx graphs see Ex. 10

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, 1/3,

+

\amp, Pseq([0.2, 0.4, 0.3], inf),

+

\midinote, Pseq([

+

Pwhite(35, 48, 1) + [-14, 0, 14],

+

Pshuf([60, 67, 70, 73], 1) + Pshuf([0, 12], 1) + [0, 4, 12],

+

], inf),

+


+

\fxOrder, Pseq([1, [1, 2], [1, 2, 3]], inf),

+

\lag, Pseq([0.17, 0.03, 0.00], inf),

+


+

\decayTime, Pseq([2.5, 0.1, 0.1], inf),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, Prand([1, 2, 3], inf),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, Pwhite(0.06, 0.1),

+

\decayTime, 1,

+


+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \echo,

+

// short delta results in additional frequency

+

\echoDelta, Pwhite(0.005, 0.01),

+

\decayTime, 0.2,

+


+

\cleanupDelay, Pkey(\decayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+


+

Example 5: Tempo control

+


+

// Tempo control works as with Pbind and can be 

+

// influenced by a number of parameters.

+


+

// As cleanup parameters of PbindFx are passed in seconds,

+

// tempo control can be done independent from making cleanup time changes

+

// (though you might do so as well)

+


+

// The use of a dedicated TempoClock as master tempo control is a good idea.

+

// Setting tempo for individual streams can be done with 'stretch'

+


+

// The following example employs a PbindFx generator Function,

+

// the tempo of streams can be controlled individually and generally.

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// PbindFx generator Function,

+

// streams will get different midinote offsets,

+

// tempo will be read from a passed array

+


+

g = { |midiOffset, tempoArray, index|

+


+

PbindFx([

+

\instrument, \source,

+

\dur, 0.25,

+

\stretch, Pfunc { 1 / tempoArray[index] },

+

\midinote, Prand([

+

Pwhite(55, 75, 1),

+

Pn(Pshuf([60, 67, 70, 73])),

+

], inf) + midiOffset,

+


+

\fxOrder, Pn(Pshuf([1, 1, [1, 2], [1, 3]])),

+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, 0.2,

+


+

\decayTime, Pfunc { |e| rrand(0.3, 0.8) / (e.fxOrder.asArray.includes(2).if { 10 }{ 1 }) },

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, 2,

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, Pseq((1..5)/50, inf),

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \wah,

+

\mix, 0.5,

+

\resLo, 400,

+

\reHi, 2000,

+

\cutOffMoveFreq, 10,

+

\cleanupDelay, 0.01

+

]

+

) };

+


+

// master TempoClock

+


+

t = TempoClock.new;

+


+


+

// array for individual tempo factors

+


+

~tempo = [1, 1, 2]/2;

+


+

// start first player on quant grid,

+

// it refers to the tempo factor ~tempo[0]

+

// note that quant refers to the tempo of the TempoClock

+


+

x = g.(-24, ~tempo, 0).play(t, quant: 1);

+

)

+


+

// start other players on quant grid

+


+

y = g.(0, ~tempo, 1).play(t, quant: 1);

+


+

z = g.(12, ~tempo, 2).play(t, quant: 1);

+


+


+

// change player's individual tempos,

+

// note that tempo changes do not necessarily happen on quant grid,

+

// so a rhythmic "phase shift" (which can be nice) might happen

+


+

~tempo[2] = 2/3

+


+

~tempo[1] = 1/3

+


+

~tempo[0] = 1

+


+


+

// set general tempo

+


+

t.tempo = 3/4

+


+


+

// stop players individually

+


+

x.stop;

+


+

y.stop;

+


+

z.stop;

+


+


+

// stop clock

+


+

t.stop;

+


+


+


+


+

Example 6: Further external routing

+


+

// This means the use of buses, which are not internally used by PbindFx's event Function.

+

// As shown in Ex.2d it can be useful to route PbindFx's out to an external reverb,

+

// Vice versa data can be read from external buses, from source synths as well as from fx synths.

+

// Audio routing benefits from the possibility to pass groups to PbindFx.

+

// Then all temporary groups, generated during playing the PbindFx,

+

// are enclosed by it and node order can be clearly defined.

+

// For audio bus routing better use In.ar than mapping with asMap,

+

// that way matching of ins and outs of fx chains is checked and it avoids 

+

// issues with using asMap and stopping the external source (occuring at least in SC 3.6.6). 

+


+


+

Example 6a: Source synth reading audio modulation signals from external buses

+


+

// source synth based on SinOsc and additional ring modulation,

+

// while reading from an audio bus with no signal, it outputs only the sine

+


+

(

+

SynthDef(\source_mod, { |out = 0, freq = 400, decayTime = 0.5,

+

attackTime = 0.005, amp = 0.1, modIn, gate = 1|

+

var env, sig;

+

sig = Decay.ar(Impulse.ar(0), decayTime, SinOsc.ar(freq) * (1 + In.ar(modIn)));

+

env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2);

+

Out.ar(out, sig ! 2 * env)

+

}).add;

+

)

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// new group and bus for the modulation signal

+

g = Group.new;

+

a = Bus.audio(s, 1);

+


+

// play source with spat effect only

+

p = PbindFx([

+

\instrument, \source_mod,

+

\dur, 0.25,

+

\amp, 0.1,

+

\midinote, Prand([

+

Pwhite(80, 90, 1),

+

Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf),

+

], inf),

+

+

\fxOrder, 1, 

+


+

\modIn, a,

+

// to enable this reading the fx chain check must know

+

\otherBusArgs, [\modIn],

+

\group, g,

+


+

\decayTime, Pwhite(0.2, 2),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, Prand([1, 2, 10], inf),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+


+

// while playing PbindFx, play modulation synth to dedicated bus,

+

// placing before group ensures that all generated synths can read from the bus

+


+

x = { Out.ar(a, SinOsc.ar(500, 0, 0.5)) }.play(target: g, addAction: \addBefore);

+


+

// no modulation again

+


+

x.free;

+


+


+

// modulation with other signal

+


+

y = { Out.ar(a, Pulse.ar(700, 0.5, 0.5)) }.play(target: g, addAction: \addBefore);

+


+


+

// add a further modulation signal

+


+

z = { Out.ar(a, Formant.ar(700, 1200, mul: 0.5)) }.play(target: g, addAction: \addBefore);

+


+


+

// formant modulation only

+


+

y.free;

+


+

// stop it also

+


+

z.free;

+


+


+

// stop and PbindFx cleanup

+


+

q.stop;

+


+


+

// cleanup of other resources, free bus and group

+


+

(

+

g.free;

+

a.free;

+

)

+


+


+

Example 6b: Fx synths reading audio modulation signals from external buses

+


+

(

+

// simple sine source synth

+

SynthDef(\source_sine, { |out = 0, freq = 400, decayTime = 0.5,

+

attackTime = 0.005, amp = 0.1, gate = 1|

+

var env, sig;

+

sig = Decay.ar(Impulse.ar(0), decayTime, SinOsc.ar(freq));

+

env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2);

+

Out.ar(out, sig ! 2 * env)

+

}).add;

+


+

// ring modulation fx synth, expecting to read the modulation signal from a bus

+

SynthDef(\ring, { |out, in, modIn, amp = 2, mix = 0.5|

+

var sig, inSig = In.ar(in, 2);

+

sig = inSig * In.ar(modIn, 1);

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+

)

+


+

// spat SynthDef from Ex. 1a, see also extended server resources defined there

+


+

(

+

// new group and buses for the modulation signal

+

g = Group.new;

+


+

a = Bus.audio(s, 1);

+

b = Bus.audio(s, 1);

+


+

// two ring modulation fxs

+

p = PbindFx([

+

\instrument, \source_sine,

+

\dur, 0.25,

+

\amp, 0.12,

+

\midinote, Prand([

+

Pwhite(80, 90, 1),

+

Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf),

+

], inf),

+


+

\group, g,

+


+

\fxOrder, Pn(Pshuf([1, [1, 2], [1, 3]])),

+

\decayTime, Pwhite(0.2, 2),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, Prand([1, 2, 10], inf),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \ring,

+

// need the index explicitely here

+

\modIn, a.index,

+

// to enable this reading the fx chain check must know

+

\otherBusArgs, [\modIn],

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \ring,

+

\modIn, b.index,

+

// to enable this reading the fx chain check must know

+

\otherBusArgs, [\modIn],

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+


+

// now live change of modulation as in Ex. 6a, but this applies only to one of three events

+


+

x = { Out.ar(a, SinOsc.ar(500, 0, 0.5)) }.play(target: g, addAction: \addBefore);

+


+


+

// also modulate events where fx reads from b

+


+

y = { Out.ar(b, Pulse.ar(700, 0.5, 0.5)) }.play(target: g, addAction: \addBefore);

+


+


+

// add a further modulation signal

+


+

z = { Out.ar(a, Formant.ar(700, 1200, mul: 0.5)) }.play(target: g, addAction: \addBefore);

+


+


+

// remove two others

+


+

x.free;

+


+

y.free;

+


+


+

// stop it also

+


+

z.free;

+


+


+

// stop and PbindFx cleanup

+


+

q.stop;

+


+


+

// cleanup of other resources, free buses and group

+


+

(

+

g.free;

+

a.free;

+

b.free;

+

)

+


+


+

Example 6c: Controlling effects with LFOs

+


+

// control the amount / mix of an effect continously

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// bus for LFO control

+

c = Bus.control(s, 1);

+


+

// play source with spat and wah-wah effect,

+

// as initially bus value is zero there is no wah at start

+


+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.25,

+

\amp, 0.15,

+

\midinote, Prand([

+

Pwhite(80, 90, 1),

+

Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf),

+

], inf),

+

\fxOrder, [1, 2], 

+

\decayTime, Pwhite(0.2, 2),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, 2, 

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \wah,

+

// maps each fx synth's mix input to the control bus

+

\mix, c.asMap,

+

// other params might still be controlled per event

+

\cutOffMoveFreq, Pseq([5, 20], inf),

+

\cleanupDelay, 0.01

+

]

+

);

+


+

q = p.play;

+

)

+


+

// chime in with wah from 0 (start phase == -pi/2)

+


+

x = { Out.kr(c, SinOsc.kr(0.15, -pi/2).range(0, 0.8)) }.play

+


+


+

// stop and free resources

+


+

(

+

q.stop;

+

x.free;

+

c.free;

+

)

+


+


+

Example 7: Replacement

+


+

// Replacement can affect certain key streams only or whole source resp.

+

// fx patterns, the latter can be done with using the option of 

+

// passing source / fx patterns instead of lists.

+


+

Example 7a: Replacement restricted to key streams

+


+

// This can be done with Pbind + Pdefn or Pbind + PL,

+

// a specific possibility with PbindFx is the replacement of \fxOrder

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

~midi = PLseq([60, 60, 60, 62]);

+

~fxs = PLseq([0, 0, 1, 3]);

+


+

// Pdefn(\midi, Pseq([60, 60, 60, 62], inf));

+

// Pdefn(\fxs, Pseq([0, 0, 1, 3], inf));

+


+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.25,

+

\midinote, PL(\midi), // Pdefn(\midi),

+

\fxOrder, PL(\fxs), // Pdefn(\fxs),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, 0.15,

+


+

\decayTime, 0.2,

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, 2,

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, 0.06,

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \wah,

+

\cutOffMoveFreq, Pseq([5, 20], inf),

+

\cleanupDelay, 0.01

+

]

+

);

+


+

q = p.play;

+

)

+


+


+

// exchange midinote and effect sequencing on the fly

+


+

~midi = PLseq([60, 62, 63]);

+


+

~fxs = PLseq([1, [1, 2], [1, 3], [1, 2, 3]]);

+


+

(

+

~midi = PLshufn([60, 62, 63]) +

+

PLshufn([-24, -12, 0]) +

+

PLshufn([0, [0, 7], [0, 7, 12]]);

+

)

+


+


+

// stop and free resources

+


+

q.stop;

+


+


+

Example 7b: Replacement of source and fx patterns

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// define source and effect patterns

+


+

~midi = PLseq([60, 60, 62, 63]);

+

~fxs = PLseq([1, [1, 2], [1, 3], [1, 2, 3]]);

+


+

~src = Pbind(

+

\instrument, \source,

+

\dur, 0.25,

+

\midinote, PL(\midi),

+

\fxOrder, PL(\fxs),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, 0.15,

+


+

\decayTime, 0.2,

+

\cleanupDelay, Pkey(\decayTime)

+

);

+


+


+

~fx1 = Pbind(

+

\fx, \spat,

+

\freq, 2,

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

);

+


+

~fx2 = Pbind(

+

\fx, \echo,

+

\echoDelta, 0.06,

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

);

+


+

~fx3 = Pbind(

+

\fx, \wah,

+

\cutOffMoveFreq, Pseq([5, 20], inf),

+

\cleanupDelay, 0.01

+

);

+


+

// pass PLx or Pdef placeholder patterns to PbindFx

+

p = PbindFx(PL(\src), PL(\fx1), PL(\fx2), PL(\fx3));

+


+

q = p.play;

+

)

+


+


+


+

(

+

// chorus fx

+


+

SynthDef(\chorus, { |out, in, amp = 1, loDelay = 0.001, hiDelay = 0.005,

+

maxDelayTime = 0.1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

inSig = Mix.fill(10, { |i|

+

DelayL.ar(inSig, maxDelayTime, LFDNoise3.ar(2).range(loDelay, hiDelay))

+

});

+

sig = inSig * amp / 2;

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+

)

+


+

// replace on the fly, fxOrder sequencing stays the same, but effect changes

+


+

(

+

~fx3 = Pbind(

+

\fx, \chorus,

+

\maxDelayTime, 0.01,

+

\loDelay, 0.001,

+

\hiDelay, 0.01,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

);

+

)

+


+

(

+

// new source SynthDef

+


+

SynthDef(\source_pulse, { |out = 0, freq = 400, decayTime = 0.5,

+

attackTime = 0.005, amp = 0.1, gate = 1|

+

var env, sig;

+

sig = Decay.ar(Impulse.ar(0), decayTime, Pulse.ar(freq));

+

env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2);

+

Out.ar(out, sig ! 2 * env)

+

}).add;

+

)

+


+

// replace source, building of phrases with rests

+


+

(

+

~src = Pbind(

+

\instrument, \source_pulse,

+

\dur, Pn(Pshuf([1, 1, 2, 2, 2, 2, 2, 4, Rest(5)], inf)) / 8,

+

\midinote, PL(\midi) + Pn(Pshuf([-24, -19, 0, 19, 24], inf)),

+

\fxOrder, PL(\fxs),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, 0.1,

+


+

\decayTime, 0.1,

+

\cleanupDelay, Pkey(\decayTime)

+

);

+

)

+


+

q.stop;

+


+


+

Example 7c: Replacement with Pbindef

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// source and fxs passed as Pbindefs

+


+

// list of instrument symbols

+

i = [\src, \fx1, \fx2, \fx3];

+


+

Pbindef(\src,

+

\instrument, \source,

+

\dur, 0.25,

+

\midinote, Pseq([60, 60, 60, 62], inf),

+

\fxOrder, Pseq([0, 0, 1, 3], inf),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, 0.15,

+


+

\decayTime, 0.2,

+

\cleanupDelay, Pkey(\decayTime)

+

);

+


+

Pbindef(\fx1,

+

\fx, \spat,

+

\freq, 2,

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

);

+


+

Pbindef(\fx2,

+

\fx, \echo,

+

\echoDelta, 0.06,

+

\decayTime, Pwhite(0.3, 1.8),

+

\cleanupDelay, Pkey(\decayTime)

+

);

+


+

Pbindef(\fx3,

+

\fx, \wah,

+

\cutOffMoveFreq, Pseq([5, 20], inf),

+

\cleanupDelay, 0.01

+

);

+


+


+

p = PbindFx(*i.collect { |x| Pbindef(x) });

+


+

q = p.play;

+

)

+


+


+

// replace some of source's key streams

+


+

(

+

Pbindef(\src,

+

\midinote, Pn(Pshuf([60, 62, 63])) +

+

Pn(Pshuf([-24, -12, 0])) +

+

Pn(Pshuf([0, [0, 7], [0, 7, 12]])),

+

\fxOrder, Pseq([[1, 3], [1, 2, 3]], inf)

+

)

+

)

+


+

// replace some of an effect's key streams

+

// note: this kind of multiple key replacement in Pbindef doesn't work with SC 3.5

+


+

(

+

Pbindef(\fx3,

+

\fx, \wah,

+

[\resLo, \resHi], Pwrand([[200, 300], [1500, 2000]], [0.8, 0.2], inf),

+

\cutOffMoveFreq, Pseq([1, 5, 20], inf),

+

\cleanupDelay, 0.01

+

)

+

)

+


+

q.stop;

+


+


+

// before playing again do Pbindef cleanup

+


+

i.do { |x| Pbindef(x).clear };

+


+


+


+

Example 8: GUI control

+


+

// control of fx params with VarGui

+

// control of fx sequencing by code

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

// ensure we are in top envir

+

currentEnvironment = topEnvironment;

+


+

// pattern for fxOrder sequencing

+

// we want to exchange this on the fly later on

+


+

~fxs = PLshufn([1, 2, 3, [2, 3], [1, 2, 3]]);

+


+

p = PbindFx([

+

\instrument, \source,

+

\dur, PL(\dur),

+

\degree, PLshufn(\degree),

+

// Spec returns a float, so write like this

+

\octave, Pfunc { rrand(~octaveLo.asInteger, ~octaveHi.asInteger) },

+


+

// we want to read from code in top envir

+

\fxOrder, PL(\fxs, envir: topEnvironment),

+


+

\lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } },

+

\amp, PL(\amp),

+


+

\attackTime, PLwhite(\attackTimeLo, \attackTimeHi),

+

\decayTime, PLwhite(\decayTimeLo, \decayTimeHi),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, PLwhite(\spatFreqLo, \spatFreqHi),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, PL(\echoDelta),

+

\decayTime, PLwhite(\echoDecayLo, \echoDecayHi),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \wah,

+

\resLo, PLwhite(\wahResLo, \wahResHi),

+

\cutOffMoveFreq, PL(\wahCutOffMoveFreq),

+

\mix, PL(\wahMix),

+

\cleanupDelay, 0.01

+

]

+

);

+


+

v = VarGui([

+

\degree, { |i| [0, 6, \lin, 1, i+2] }!4,

+

\octaveLo, [3, 6, \lin, 1, 4],

+

\octaveHi, [3, 6, \lin, 1, 6],

+

\dur, [0.2, 0.3, \lin, 0, 0.2],

+

\attackTimeLo, [0.01, 0.1, \lin, 0, 0.02],

+

\attackTimeHi, [0.01, 0.1, \lin, 0, 0.05],

+

\amp, [0.0, 0.5, \lin, 0, 0.2],

+


+

\decayTimeLo, [0.1, 0.5, \lin, 0, 0.2],

+

\decayTimeHi, [0.1, 0.5, \lin, 0, 0.4],

+


+

\spatFreqLo, [0.1, 10, \lin, 0, 0.5],

+

\spatFreqHi, [0.1, 10, \lin, 0, 2],

+


+

\echoDelta, [0.03, 0.1, \lin, 0, 0.05],

+

\echoDecayLo, [0.1, 2, \lin, 0, 0.3],

+

\echoDecayHi, [0.1, 2, \lin, 0, 1.8],

+


+

\wahCutOffMoveFreq, [0, 10, \lin, 0, 5],

+

\wahResLo, [100, 3000, \exp, 0, 200],

+

\wahResHi, [100, 3000, \exp, 0, 2000],

+

\wahMix, [0, 1, \lin, 0, 1]

+

], stream: p

+

).gui(

+

sliderWidth: 350,

+

labelWidth: 120,

+

varColorGroups: (0..20).clumps([12, 2, 3, 4]);

+

);

+

)

+


+

// start playing with gui and test params

+

// change of echoDelta necessarily causes a delay as 

+

// delays for events without echo have to be adapted

+


+


+

// change effect order sequencing

+


+

~fxs = PLseq([1, 1, 2, 2, 3, 3]);

+


+

// only spat + wah

+


+

~fxs = [1, 3];

+


+


+

// no effects

+


+

~fxs = 0;

+


+


+

// kind of polyrhythm with effects and pitches

+

// all 4 pitch classes are permanently reordered by PLshufn

+

// fixed effect sequencing

+


+

~fxs = PLseq([1, [1, 2], [1, 2, 3]]);

+


+


+

// stop by gui or explicitely

+


+

v.streams[0].stop;

+


+


+

Example 9: Using value conversions with fx data

+


+

// Effects can produce their own characteristic frequencies.

+

// For this it can be practical to use Event's value conversion framework.

+


+

(

+

// filter bank effect, level of signal very much depends on input frequencies

+

SynthDef(\klank, { |out, in, freq = 400, add = 7, amp = 1, ringTime = 0.1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = DynKlank.ar(`[freq * [1, add.midiratio], nil, ringTime ! 2], inSig) * amp / 100;

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+

)

+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, 0.2,

+

\amp, Pseq([0.15, 0.1, 0.1], inf),

+

\midinote, Pn(Pshuf([36, 36, 48, 48, 60, 65, 67])) +

+

Pseq([Pn(0, 40), Pn(7, 10), Pn(-5, 10)], inf) +

+

Pn(Pshuf([0, 0, 0, [0, 7], [0, 9], [0, 14]])),

+

\decayTime, Pwhite(0.8, 1.5),

+

\fxOrder, Pn(Pshuf([1, [1, 2], [1, 2]])),

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, Prand([1, 2, 3] / 5, inf),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \klank,

+

\octave, Pwhite(5, 8),

+

// passing notes instead of frequencies is more pleasant here

+

// resulting signal is louder if pitches are near overtones of source

+

\note, Pn(Pshuf([0, 4, 5, 7])), 

+

\add, Prand([7, 12], inf),

+

\decayTime, 0.1,

+

\ringTime, Pwhite(0.1, 0.3),

+

\mix, 0.7,

+

\cleanupDelay, Pkey(\ringTime)

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 10: Parallel effects and arbitrary effect graphs

+


+

Example 10a: Parallel effects

+


+


+

// here source is routed to echo #1 and echo #2 in parallel,

+

// echo #1 (fx index 2) is a "classical" echo whereas echo #2 (fx index 3), 

+

// due to short echoDelta, results in an additional frequency.

+

// The output of echo #2 is routed to a wah-wah, echo #1 directly to out.

+


+

+


+


+

// SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \source,

+

\dur, Pseq([Pn(0.2, { rrand(8, 12) }), Pwhite(2.0, 4.0, 1)], inf),

+

\amp, 0.3,

+

\midinote, Prand([

+

Pwhite(80, 90, 1),

+

Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf),

+

], inf),

+

+

\fxOrder, `(0: 1, 1: [2, 3], 3: 4),

+

// compare with this version, where echo #1 is less present, as it also goes to wah

+

// \fxOrder, `(0: 1, 1: [2, 3], 3: 4, 2: 4),

+

+

\decayTime, 0.1, 

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \spat,

+

\freq, Prand([0.1, 0.8], inf),

+

\maxDelayTime, 0.001,

+

\cleanupDelay, 0.1

+

],[

+

\fx, \echo,

+

\echoDelta, 0.1,

+

\decayTime, 3,

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \echo,

+

\echoDelta, Pwhite(0.01, 0.05),

+

\decayTime, 5,

+

\amp, 0.5,

+

\cleanupDelay, Pkey(\decayTime)

+

],[

+

\fx, \wah,

+

\mix, 0.7,

+

\cutOffMoveFreq, Pseq([1, 2, 5, 10], inf),

+

\cleanupDelay, 0.05

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 10b: Modulation graphs

+


+

// A generalized modulating effect node has two ins: carrier and modulator.

+

// Fx convention of PbindFx demands one single In ugen per fx synth, but two ins  

+

// can simply be handled by a 2-channel In ugen and hard-panned input signals.

+


+

(

+

// sine source

+

SynthDef(\sine_adsrFixed, { |out = 0, freq = 400, decayTime = 0.5,

+

att = 0.005, dec = 0.01, sus = 0.2, rel = 0.3, susLevel = 0.5, amp = 0.1|

+

var env, sig = SinOsc.ar(freq);

+

env = EnvGen.kr(Env([0, 1, susLevel, susLevel, 0], [att, dec, sus, rel]), doneAction: 2);

+

Out.ar(out, sig ! 2 * env * amp)

+

}).add;

+


+

// amplitude modulation synth

+

SynthDef(\ampMod, { |out, in, dev = 1, amp = 1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = inSig[0] * (inSig[1] * dev + DC.ar(1)) * amp;

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+

// phase modulation synth

+

SynthDef(\phaseMod, { |out, in, maxDelay = 0.1, dev = 1, amp = 1, mix = 1|

+

var sig, inSig = In.ar(in, 2);

+

sig = DelayC.ar(inSig[0], maxDelay, maxDelay * dev * inSig[1], amp);

+

Out.ar(out, (1 - mix) * inSig + (sig * mix));

+

}).add;

+


+

// modulator synths, no Ins 

+


+

SynthDef(\sineM, { |out, in, freq = 100|

+

    Out.ar(out, [0, SinOsc.ar(freq)]);

+

}).add;

+


+

SynthDef(\pulseM, { |out, in, freq = 100, width = 0.5|

+

Out.ar(out, [0, Pulse.ar(freq, width, 2)]);

+

}).add;

+


+

SynthDef(\sawM, { |out, in, freq = 100|

+

Out.ar(out, [0, Saw.ar(freq)]);

+

}).add;

+

)

+


+


+

// blend of AM events

+


+

// spat SynthDef from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

\instrument, \sine_adsrFixed,

+

\dur, 1,

+

\susLevel, 1,

+

\att, 5,

+

\sus, 0,

+

\rel, 5,

+

\amp, 0.03,

+

\midinote, Pwhite(40, 80),

+

\fxOrder, `(0: 1, 3: 1, 1: 2),

+


+

\decayTime, 1,

+

\cleanupDelay, 12

+

],[

+

\fx, \ampMod,

+

\dev, Pwhite(0.1, 0.6)

+

],[

+

\fx, \spat,

+

\freq, Pwhite(0.2, 2),

+

\maxDelayTime, 0.005,

+

\cleanupDelay, Pkey(\maxDelayTime)

+

],[

+

\fx, \pulseM,

+

\freq, Pwhite(200, 1000)

+

]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+

Example 10c: Modulation graphs, changed per event

+


+

// fx graphs corresponding to fxOrder `(0:1, 4:1, 1:6) and `(0:1, 5:1, 1:6), src = \sine_adsrFixed:

+


+

+

+

+

// fx graph corresponding to fxOrder `(0:2, 3:2, 2:6), src = \sine_adsrFixed:

+

+

+


+

// SynthDefs from Ex. 10b

+

// spat SynthDefs from Ex. 1a, see also extended server resources defined there

+


+

(

+

p = PbindFx([

+

        \instrument, \sine_adsrFixed,

+

        \amp, 0.01,

+

\dur, 0.3,

+

        \susLevel, 1,

+

        \att, 0.01,

+

        \sus, 0.15,

+

\rel, Pwhite(0.3, 1.2),

+

        \amp, 0.05,

+


+

        \midinote, Pwhite(30, 60) + Prand([0, [0, -12.5]], 200),

+


+

// changes between amplitude (pulse and saw) and phase modulation (sine)

+


+

        \fxOrder, Pn(Pshuf([

+

                `(0:1, 4:1, 1:6),

+

                `(0:1, 5:1, 1:6),

+

                `(0:2, 3:2, 2:6)

+

            ])),

+


+

        // equivalent:

+

        // the source stream returns pairs, where the first number indicates

+

        // the modulation type and the second number the modulator,

+

        // the collect function packs the data into the right format of a ref'd Event.

+


+

        // \fxOrder, Pn(Pshuf([ [1, 4], [1, 5], [2, 3] ]))

+

        // .collect { |x| ().putPairs([0, x[0], x[1], x[0], x[0], 6]).asRef },

+


+

        \decayTime, 2,

+

        \cleanupDelay, Pkey(\decayTime)

+

    ],[

+

        \fx, \ampMod,

+

        \dev, Pwhite(0.1, 0.5)

+

    ],[

+

        \fx, \phaseMod,

+

        \dev, Pwhite(0.03, 0.05)

+

    ],[

+

        \fx, \sineM,

+

        \freq, Pwhite(150, 700)

+

    ],[

+

        \fx, \sawM,

+

        \freq, Pwhite(150, 700)

+

    ],[

+

        \fx, \pulseM,

+

        \freq, Pwhite(150, 700)

+

    ],[

+

        \fx, \spat,

+

        \freq, Pwhite(0.1, 1),

+

        \maxDelayTime, 0.005,

+

        \cleanupDelay, Pkey(\maxDelayTime)

+

    ]

+

);

+


+

q = p.play;

+

)

+


+

q.stop;

+


+


+ + diff --git a/Help/PlaceAll.html b/Help/PlaceAll.html new file mode 100755 index 0000000..d8445c2 --- /dev/null +++ b/Help/PlaceAll.html @@ -0,0 +1,112 @@ + + + + + + + + + + + +

PlaceAll Arbitrarily nested embedding of subarrays 

+


+

Part of: miSCellaneous

+


+

Inherits from: Ppatlace

+


+

PlaceAll is integrating Ppatlace and Place (taking items as well as Patterns) and allows an arbitrary depth of nesting arrays.

+


+

See also: Place, Ppatlace

+


+


+

Creation / Class Methods

+


+

*new (list, repeats, offset)

+

+

Creates a new PlaceAll object.

+

+

list - Array which may contain subarrays. Leaves of the array tree may be 

+

Patterns, Streams or other Items to be embedded.

+

repeats - Number of list loops. Defaults to 1.

+

offset - List index offset. Defaults to 0.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

(

+

p = Pbind(

+

\midinote, PlaceAll([[60, 61], 70, [80, [81, 81.5], 82]], inf),

+

\dur, 0.2

+

);

+


+

x = p.play;

+

)

+


+

x.stop;

+


+


+

// to distinguish subarrays from arrays to be taken as output use Refs, 

+

// as wrapping in another array wouldn't do

+


+

(

+

p = Pbind(

+

\midinote, PlaceAll([[60, 61], 70, [80, `[81, 81.5], 82]], inf),

+

\dur, 0.2

+

);

+


+

x = p.play;

+

) 

+


+


+

x.stop;

+


+


+

// Items may also be Patterns or Streams

+


+

(

+

p = Pbind(

+

\midinote, PlaceAll([[60, 61], 70, [80, Pwhite(84.0, 89), 82]], inf),

+

\dur, 0.2

+

);

+


+

x = p.play;

+

) 

+


+


+

x.stop;

+

 

+


+ + diff --git a/Help/PmonoPar.html b/Help/PmonoPar.html new file mode 100755 index 0000000..025a147 --- /dev/null +++ b/Help/PmonoPar.html @@ -0,0 +1,174 @@ + + + + + + + + + + + +

PmonoPar monophonic event pattern for an arbitrary number of timed setting streams 

+


+

Part of: miSCellaneous

+


+

Inherits from: Plazy

+


+

See also: Pmono, PpolyPar, PbindFx

+


+

This is similar to Pmono, but allows an arbitrary number of differently timed setting streams in parallel.

+


+

History: PmonoPar and PpolyPar grew out of discussions on sc-users list, based on an example by Jonatan Liljedahl. Thanks to him, Ron Kuivila, user Monsieur and others for their comments on this – I then suggested classes PsetGroup and PsetFxGroup, which internally use Pgroup. Meanwhile I reworked the implementation, but it's still based on groups. I renamed PsetGroup to PmonoPar – as this makes the functionality more clear – and PsetFxGroup to PpolyPar, as it can be used with or without effect synths, the crucial point is the setting of parallel streams.

+


+

Creation / Class Methods

+


+

*new (setPatternPairs, defname, offset)

+

+

Creates a new PmonoPar object.

+

+

setPatternPairs - SequenceableCollection of SequenceableCollections containing key/value pairs.

+

Each of the inner collections represents the data of one synth setting stream.

+

Per convention key/value pairs written after a pair with \dur will cause setting, pairs before will not.

+

If keys \midinote, \note or \degree are occuring after \dur, they will be converted to a frequency value,

+

which will be used for setting the arg 'freq'.

+

defname - Symbol or String. Name of the SynthDef to be used for the synth being set.

+

Defaults to \default.

+

offset - Number. Offset to be taken for time-shifting synth init and streams. Defaults to 1e-6.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Ex. 1a: PmonoPar with differently timed streams

+


+

// per convention keys after \dur are the ones to be set

+

// playing ends after end of last stream

+


+

(

+

p = PmonoPar([

+

[

+

\dur, 1.0,

+

\pan, Pser([-0.9, 0, 0.9], 8)  

+

],[

+

\dur, 0.4,

+

\freq, Pexprand(300, 1000, 24)   

+

],[

+

\dur, 0.2,

+

\amp, Pseq([0.05, 0.3], 30)  

+

]

+

]).trace.play;

+

)

+


+


+


+

Ex. 1b: Passing values by using the value conversion framework

+


+

// if \degree, \note or \midinote are occuring after \dur,

+

// a frequency value will be calculated according to Event's usual conversion framework

+

// and used for setting the arg 'freq'.

+


+

(

+

p = PmonoPar([

+

[

+

\dur, 1.0,

+

\pan, Pser([-0.9, 0, 0.9], 8)  

+

],[

+

\dur, 0.4,

+

\midinote, Pseq((70..75), 7)

+

],[

+

\dur, 0.2,

+

\amp, Pseq([0.05, 0.3], 30)  

+

]

+

]).trace.play;

+

)

+


+


+


+

Ex. 2: Data sharing between streams of PmonoPar

+


+

// data sharing with rhythms of coinciding entry points is sure as streams are time-shifted

+


+

(

+

p = PmonoPar([

+

[

+

\dur, Prand([1, 1, 2]/3, inf).collect(~dur = _).trace,   // or:  .collect { |x| ~dur = x } .trace

+

\amp, Pseq([0.2, 0.05], 15).trace   

+

],[

+

\dur, Pfunc { ~dur / 2 },

+

\midinote, Pshuf((60..85))   

+

]

+

]).trace.play;

+

)

+


+


+

Ex. 3: Data sharing between streams of parallel PmonoPars

+


+

// data sharing between streams of same PmonoPar and streams of second PmonoPar,

+

// use of Ptpar ensures that first stream of second PmonoPar comes after first stream of first PmonoPar,

+

// consider also PpolyPar for such type of usage

+


+

(

+

p = PmonoPar([

+

[

+

\dur, Prand([1, 1, 2]/3, 40).collect(~dur = _),

+

\amp, Pseq([0.3, 0.1], 15)   

+

],[

+

\dur, Pfunc { ~dur / 2 },

+

\midinote, Pshuf((50..70))   

+

]

+

]);

+


+

q = PmonoPar([

+

[

+

\dur, Pfunc { ~dur },

+

\amp, Pseq([0.3, 0.1], 15)   

+

],[

+

\dur, Pfunc { ~dur / 3 },

+

\midinote, Pshuf((75..95), 2)   

+

]

+

]);

+


+

r = Ptpar([0, p, 1e-5, q]).trace.play

+

)

+


+


+


+


+ + diff --git a/Help/PpolyPar.html b/Help/PpolyPar.html new file mode 100755 index 0000000..41a327a --- /dev/null +++ b/Help/PpolyPar.html @@ -0,0 +1,497 @@ + + + + + + + + + + + +

PpolyPar polyphonic event pattern for an arbitrary number of timed setting streams 

+


+

Part of: miSCellaneous

+


+

Inherits from: Plazy

+


+

See also: Pmono, PmonoPar, PbindFx

+


+

This is similar to PmonoPar and allows an arbitrary number of monophonic streams as well as an arbitrary number of differently timed setting streams applied to them in parallel. Each setting action can affect an arbitrary combination of running synths. PpolyPar can be used for polyphonic sources alone as well as in combination with effects.

+


+

History: PmonoPar and PpolyPar grew out of discussions on sc-users list, based on an example by Jonatan Liljedahl. Thanks to him, Ron Kuivila, user Monsieur and others for their comments on this – I then suggested classes PsetGroup and PsetFxGroup, which internally use Pgroup. Meanwhile I reworked the implementation, but it's still based on groups. I renamed PsetGroup to PmonoPar – as this makes the functionality more clear – and PsetFxGroup to PpolyPar, as it can be used with or without effect synths, the crucial point is the setting of parallel streams.

+


+


+

Creation / Class Methods

+


+

*new (setPatternPairs, defNames, order, offset)

+

+

Creates a new PpolyPar object.

+

+

setPatternPairs - SequenceableCollection of SequenceableCollections containing key/value pairs.

+

Each of the inner collections represents the data of one synth setting stream.

+

Per convention key/value pairs written after a pair with \dur will cause setting, pairs before will not.

+

If keys \midinote, \note or \degree are occuring after \dur, they will be converted to a frequency value,

+

which will be used for setting the arg 'freq'.

+

Also per convention, if the number of setting streams (the size of setPatternPairs) equals the number

+

of synths (the size of defNames), the settings of stream i will automatically affect synth i.

+

If sizes are unequal, each collection of key/value pairs needs a pair with key \synths and a value.

+

This value can be an Integer, meaning synth i, or a SequenceableCollection of Integers, in which case all of those

+

synths will be affected by the setting. The value can also be a Pattern, so that synths to be set

+

might change from event to event (see examples).

+

defNames - SequenceableCollection of Symbols or Strings. Names of the SynthDefs to be used for the synths being set.

+

Defaults to #[\default].

+

order - SequenceableCollection of Integers indicating the order of nodes passed to defNames.

+

Defaults to nil, in that case an order 0, ... , (defNames.size - 1) is assumed, i.e. synth i comes before synth i+1.

+

offset - Number. Offset to be taken for time-shifting synth inits and streams. Defaults to 1e-6.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

Ex. 1a: PpolyPar with different instruments

+


+

// basic SynthDefs, EnvGate invents a gate arg which is necessary for release

+


+

(

+

SynthDef(\saw, { |freq = 400, freqlag = 0.0, amp = 0.1, amplag = 0.01|

+

Out.ar(0, Saw.ar(Lag.kr(freq, freqlag), VarLag.kr(amp, amplag, warp: 1)) ! 2 * EnvGate());

+

}).add;

+


+

SynthDef(\pulse, { |freq = 400, freqlag = 0.0, amp = 0.1, amplag = 0.05|

+

Out.ar(0, Pulse.ar(Lag.kr(freq, freqlag), mul: VarLag.kr(amp, amplag, warp: 1)) ! 2 * EnvGate());

+

}).add;

+


+

SynthDef(\sine, { |freq = 400, freqlag = 0.0, amp = 0.1, amplag = 0.05|

+

Out.ar(0, SinOsc.ar(Lag.kr(freq, freqlag), 0, mul: VarLag.kr(amp, amplag, warp: 1)) ! 2 * EnvGate());

+

}).add;

+

)

+


+

// simple usage, each stream is setting the corresponding instrument

+


+

// per convention keys after \dur are the ones to be set

+

// note that you'd need \freq (the SynthDef arg) 

+


+

(

+

p = PpolyPar([[

+

\dur, 1/6,

+

\amp, Pwrand([0, 0.07], [1, 7]/8, inf),

+

\midinote, Pshuf((30..68), inf)

+

],[

+

\dur, Prand([1, 1, 2]/4, inf),

+

\amp, Pwrand([0, 0.07, 0.1], [0.3, 0.3, 0.4], inf),

+

\freqlag, 0.2,

+

\amplag, Prand([0.2, 0.4], inf),

+

\midinote, Pbrown(70, 90, 5)

+

]],

+

[\saw, \pulse]

+

).play;

+

)

+


+

p.stop;

+


+


+

Ex. 1b: PpolyPar with different instruments and overlapping settings

+


+

// SynthDefs from Ex. 1a

+


+

(

+

// Function to create midinote patterns in different ranges

+


+

r = { |add = 0| Pstutter(5, Pwhite(60, 70) + add) };

+


+

// each setting stream affects two synths: those of corresponding indices of \synths,

+

// but only with one value: the Integer polled from the Pstutter stream

+


+

p = PpolyPar([[

+

\synths, [0, 1],

+

\dur, 1/6,

+

\midinote, r.(),

+

\amp, 0.04

+

],[

+

\synths, [0, 2],

+

\dur, 1/4,

+

\midinote, r.(10),

+

\amp, 0.03

+

],[

+

\synths, [1, 2],

+

\dur, 1/3,

+

\midinote, r.(20),

+

\amp, 0.05

+

]],

+

[\saw, \pulse, \sine]

+

).play

+

)

+


+

p.stop;

+


+


+

Ex. 1c: PpolyPar with different instruments, overlapping settings with array dispatch

+


+

// SynthDefs from Ex. 1a

+


+

(

+

// Similar to Ex. 1b, but the midinote pattern will cause the stream to generate arrays of two elements,

+

// they will be distributed to the indicated synths

+


+

r = { |add = 0, int = 7| Pstutter(5, Pwhite(60, 65) + [0, int] + add) };

+


+

// each setting streams affects two synths: those of corresponding indices of \synths

+


+

p = PpolyPar([[

+

\synths, [0, 1],

+

\dur, 1/6,

+

\midinote, r.(0, 5),

+

\amp, 0.04

+

],[

+

\synths, [0, 2],

+

\dur, 1/4,

+

\midinote, r.(10, 6),

+

\amp, 0.03

+

],[

+

\synths, [1, 2],

+

\dur, 1/3,

+

\midinote, r.(20, 7),

+

\amp, 0.05

+

]],

+

[\saw, \pulse, \sine]

+

).play

+

)

+


+

p.stop;

+


+


+

Ex. 2a: PpolyPar with one effect synth

+


+

(

+

// With t_gate a percussive envelope will be triggered,

+

// so articulation can be achieved within a monophonic stream.

+

// This is similar to Pbind, though only if envelopes are shorter than entry time differences. 

+


+

SynthDef(\test, { |out = 0, freq = 440, att = 0.01, rel = 0.1, amp = 0.1, t_gate = 1|

+

var sig = Saw.ar(freq, amp), delayedSig;

+

sig = sig!2 * EnvGen.ar(Env.perc(att, rel), t_gate);

+

// add some spatial variance by LFO on delaytime

+

delayedSig = DelayL.ar(sig, delaytime: { LFDNoise3.kr(0.5).range(0.005, 0.02) } ! 2);

+

Out.ar(out, delayedSig * EnvGate())

+

}).add;

+


+

// Effect synthdefs with in and out bus,

+

// both get an EnvGate which introduces a gate arg for proper release,

+

// one could also add a gate arg and an EnvGen using it.

+


+

// wet/dry-relation is fixed, considering the example with fx chain a bypass arg is introduced

+


+

SynthDef(\echo, { |out = 0, in, maxdtime = 0.2, dtime = 0.2, decay = 3, amp = 0.5, bypass = 0|

+

var sig, insig;

+

insig = In.ar(in, 2);

+

sig = CombL.ar(insig, maxdtime, dtime, decay, amp, add: insig) * EnvGate();

+

Out.ar(out, bypass * insig + ((1 - bypass) * sig));

+

}).add;

+


+


+

SynthDef(\wah, { |out = 0, in, freqLo = 200, freqHi = 5000, modFreq = 10, amp = 0.7, bypass = 0|

+

var sig, insig;

+

insig = In.ar(in, 2);

+

sig = RLPF.ar(

+

insig,

+

LinExp.kr(LFDNoise1.kr(modFreq), -1, 1, freqLo, freqHi),

+

0.1,

+

amp,

+

insig * 0.3

+

).softclip * 0.8 * EnvGate();

+

Out.ar(out, bypass * insig + ((1 - bypass) * sig));

+

}).add;

+

)

+


+


+

// Whereas node order is done by PpolyPar, bus handling is the user's responsibility,

+

// it looks more flexible to me to define buses separately.

+


+

// one fx

+


+

b = Bus.audio(s, 2);

+


+

(

+

p = PpolyPar([[

+

\dur, 0.5,

+

\amp, 0.2,

+

\out, b,

+

\t_gate, 1,

+

\midinote, Pwhite(50, 100)

+

],[

+

// dur = inf causes just a running fx synth, none of its args is set by a stream

+

\dur, inf,

+

\in, b,

+

\dtime, 0.1,

+

\decay, 3

+

]],

+

[\test, \echo]

+

).play

+

)

+


+

p.stop;

+


+

b.free;

+


+

+

Ex. 2b: PpolyPar with more effect synths

+


+

// SynthDefs from Ex. 2a

+


+

(

+

b = Bus.audio(s, 2);

+

c = Bus.audio(s, 2);

+

)

+


+


+

// still none of the effects is set by a stream

+


+

(

+

p = PpolyPar([[

+

// values before \dur are not sent to server, so do this work here:

+

// echo (out b) is coupled with short release time

+

// wah (out c) is coupled with longer release time

+

\data, Prand([[b, 0.1], [c, 0.5]], inf),

+

\dur, Prand([1, 1, 2]/5, inf),

+

\amp, 0.3,

+

// data dispatch from above, these values will be sent

+

\rel, Pkey(\data).collect(_[1]),

+

\out, Pkey(\data).collect(_[0]),

+

\t_gate, 1,

+

\midinote, Pwhite(50, 100)

+

],[

+

\dur, inf,

+

\in, b,

+

\out, 0,

+

\dtime, 0.1,

+

\decay, 3

+

],[

+

\dur, inf,

+

\in, c,

+

\amp, 0.3

+

]],

+

[\test, \echo, \wah]

+

).play;

+

)

+


+

p.stop;

+


+

(

+

b.free;

+

c.free;

+

)

+


+


+

Ex. 2c: PpolyPar with more effect synths and streamed setting

+


+

// SynthDefs from Ex. 2a

+


+

(

+

b = Bus.audio(s, 2);

+

c = Bus.audio(s, 2);

+

)

+


+


+

// effects set by streams

+


+

(

+

p = PpolyPar([[

+

// values before \dur are not sent to server, so do this work here:

+

// echo (out b) is coupled with short release time

+

// wah (out c) is coupled with longer release time

+

\data, Prand([[b, 0.1], [c, 0.5]], inf),

+

// will get "bars" of length 4/5

+

\dur, Pn(Pshuf([1, 1, 2]/5)),

+

\amp, 0.3,

+

// data dispatch from above, these values will be sent

+

\rel, Pkey(\data).collect(_[1]),

+

\out, Pkey(\data).collect(_[0]),

+

\t_gate, 1,

+

\midinote, Pwhite(50, 100)

+

],[

+

\dur, 4/5,

+

\in, b,

+

// change delaytime per "bar", random add avoids repeating echo frequencies

+

\dtime, Pshuf([1, 2, 4]/40, inf) + (Pwhite(-0.5, 0.5)/40),

+

\decay, 3

+

],[

+

\dur, 4/5,

+

\in, c,

+

// change modFreq per "bar"

+

\modFreq, Pshuf((1..20), inf),

+

\amp, 0.3

+

]],

+

[\test, \echo, \wah]

+

).play

+

)

+


+

p.stop;

+


+

(

+

b.free;

+

c.free;

+

)

+


+


+

Ex. 2d: PpolyPar with more effect synths, streamed setting and more than one setting stream per synth

+


+

// SynthDefs from Ex. 2a

+


+

(

+

b = Bus.audio(s, 2);

+

c = Bus.audio(s, 2);

+

)

+


+


+

// Now we have more setting streams than synths,

+

// so we need to define which synth is to be set by which stream,

+

// this done via the \synths key, which must be contained in every collection of pairs.

+


+

(

+

p = PpolyPar([[

+

\synths, 0,

+

// values before \dur are not sent to server, so do this work here:

+

// echo (out b) is coupled with short release time

+

// wah (out c) is coupled with longer release time

+

\data, Prand([[b, 0.1], [c, 0.5]], inf),

+

// will get "bars" of length 4/5

+

\dur, Pn(Pshuf([1, 1, 2]/5)),

+

\amp, 0.3,

+

// data dispatch from above, these values will be sent

+

\rel, Pkey(\data).collect(_[1]),

+

\out, Pkey(\data).collect(_[0]),

+

\t_gate, 1

+

],[

+

// stream setting frequency 

+

\synths, 0,

+

\dur, 1/20,

+

\midinote, Pshuf((45..90), inf)

+

],[

+

\synths, 1,

+

\dur, 4/5,

+

\in, b,

+

// change delaytime per "bar", random add avoids repeating echo frequencies

+

\dtime, Pshuf([1, 2, 4]/40, inf) + (Pwhite(-0.5, 0.5)/40),

+

\decay, 3

+

],[

+

\synths, 2,

+

\dur, 4/5,

+

\in, c,

+

// change modFreq per "bar"

+

\modFreq, Pshuf((1..20), inf),

+

\amp, 0.3

+

]],

+

[\test, \echo, \wah]

+

).play

+

)

+


+

p.stop;

+


+

(

+

b.free;

+

c.free;

+

)

+


+


+

Ex. 2e: PpolyPar with effect chain and streamed fx repatching

+


+

// SynthDefs from Ex. 2a

+


+

(

+

b = Bus.audio(s, 2);

+

c = Bus.audio(s, 2);

+

)

+


+

// Here effects are chained in order - see buses passed to \in and \out

+

// Again more setting streams than synths, so the \synths key is needed.

+


+

(

+

p = PpolyPar([[

+

\synths, 0, // source synth

+

// will get "bars" of length 4/5

+

\dur, Pn(Pshuf([1, 1, 2]/5)),

+

\amp, 0.3,

+

\rel, 0.2,

+

\out, b,

+

\t_gate, 1

+

],[

+

// freq rhythm might differ from envelope rhythm (stream 0)

+

\synths, 0,

+

\dur, Pn(Pshuf([1, 1, 2]/5)),

+

\midinote, Pshuf((45..90), inf)

+

],[

+

\synths, 1, // echo

+

\dur, 4/5,

+

\in, b, // gets from source and sends to wah

+

\out, c,

+

// change delaytime per "bar", random add avoids repeating echo frequencies

+

\dtime, Pshuf([1, 2, 4]/20, inf) + (Pwhite(-0.5, 0.5)/20),

+

\decay, 3

+

],[

+

\synths, 2, // wah

+

\dur, 4/5,

+

\in, c, // gets from echo, sends to out 0 by default

+

// change modFreq per "bar"

+

\modFreq, Pshuf((1..20), inf),

+

\amp, 0.3

+

],[

+

// this stream determines effects in action by setting bypass args of both fx synths

+

\synths, [1, 2],

+

\dur, 1/5, 

+

// alternate bypassing of wah synth

+

\bypass, Pseq([[0, 0], [0, 1]], inf)

+

]],

+

[\test, \echo, \wah]

+

).play

+

)

+


+

p.stop;

+


+

(

+

b.free;

+

c.free;

+

)

+


+


+


+


+ + diff --git a/Help/Pshufn.html b/Help/Pshufn.html new file mode 100755 index 0000000..7e2e89d --- /dev/null +++ b/Help/Pshufn.html @@ -0,0 +1,76 @@ + + + + + + + + + + + +

Pshufn Pshuf with continuing permutations 

+


+

Part of: miSCellaneous

+


+

Inherits from: Pn

+


+

Variation of Pshuf which scrambles the list with every repeat. 

+


+

See also: Pshuf, PLshuf, PLshufn, PLx suite

+


+


+

Creation / Class Methods

+


+

*new (list, repeats)

+

+

Creates a new Pshufn object.

+

+

list - list to be scrambled.

+

repeats - number of permutations. Defaults to 1.

+


+

+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

(

+

p = Pbind(

+

\midinote, Pshufn((70..73), inf),

+

\dur, 0.2

+

);

+

)

+


+

x = p.play;

+


+

x.stop;

+


+


+ + diff --git a/Help/Psieve.html b/Help/Psieve.html new file mode 100755 index 0000000..1d5cbbb --- /dev/null +++ b/Help/Psieve.html @@ -0,0 +1,40 @@ + + + + + + + + + + + +

Psieve Abstract superclass of sieve patterns

+


+

Part of: miSCellaneous

+


+

Inherits from: Pattern

+


+

PSVx sieve patterns inherit from Psieve. Normally you don't have to use Psieve directly.

+


+

See also: Sieves and Psieve patterns, Sieve, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+

Instance Methods

+


+

embedInStream

+

+ + diff --git a/Help/PsymNilSafe.html b/Help/PsymNilSafe.html new file mode 100755 index 0000000..ec1feca --- /dev/null +++ b/Help/PsymNilSafe.html @@ -0,0 +1,88 @@ + + + + + + + + + + + +

PsymNilSafe Psym variant that avoids hangs if all referenced patterns return nil

+


+

Part of: miSCellaneous

+


+

Inherits from: Psym

+


+

This adapts an idea of James Harkins' PnNilSafe (ddwPatterns quark) for Psym. If all patterns in the Dictinonary return nil, then Psym's embedInStream can produce an infinite loop, as it never yields. PnNilSafe can't be wrapped around Psym, but the check with logical time can be built into Psym itself. The wrapping into PsymNilSafe can shortly be written by applying 'symplay' instead of 'play'.

+


+

See also: Psym, PLx and live coding with Strings

+


+


+

Creation / Class Methods

+


+

*new (pattern, dict, maxNull)

+

+

Creates a new PsymNilSafe object. pattern expects a pattern of Symbols, dict the lookup dictionary and defaults to the current Environment. maxNull is the number of events with delta = 0 after which PsymNilSafe's method 'embedInStream' yields and thus stops a potentially endless loop. maxNull defaults to 128.

+

+


+

Instance Method for Class Pattern

+

 

+

aPattern.symplay(dict, clock, protoEvent, quant, maxNull = 128)

+

+

Play a pattern wrapped into a PsymNilSafe. Arguments clock, protoEvent and quant work as with playing a Pattern, arguments dict and maxNull work as with PsymNilSafe.new.

+

+

+

+

Example

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+

(

+

x = Pbind(\midinote, Pseries(60, 1, 10), \dur, 0.5).asStream;

+

y = Pbind(\midinote, Pseries(90, -1, 10), \dur, 0.5).asStream;

+


+

z = Pseq([2, 3, 1, 2], 1).asStream;

+


+

~a = Pfuncn({ x.next(()) }, { z.next });

+

~b = Pfuncn({ y.next(()) }, { z.next });

+


+

PsymNilSafe(Pseq("ab", inf)).trace.play;

+


+

// shorter with method 'symplay':

+

// trace indicates all events with delta = 0 (maxNull = 128) in the post window

+

// Pseq("ab", inf).trace.symplay

+


+


+

// ATTENTION: with Psym the example leads to a SC hang !

+

// Psym(Pseq("ab", inf), currentEnvironment).trace.play

+

)

+ + diff --git a/Help/Sieve.html b/Help/Sieve.html new file mode 100755 index 0000000..70ef5d5 --- /dev/null +++ b/Help/Sieve.html @@ -0,0 +1,720 @@ + + + + + + + + + + + +

Sieve Container class for sieve lists 

+


+

Part of: miSCellaneous

+


+

Container for a list of ascending integers as 'points' or 'intervals' .

+


+

See also: Sieves and Psieve patterns, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+


+

Creation / Class Methods

+


+

*newEmpty

+

+

Creates a new empty Sieve object.

+


+

*new (...data)

+

+

Creates a new Sieve object in mode 'points'.

+

+

data - A generator and an optional integer limit, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*new_i (...data)

+

+

Creates a new Sieve object in mode 'intervals'.

+

+

data - A generator and an optional integer limit, which is included when reached.

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*new_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offset.

+

+

data - A generator, an integer offset and an optional integer limit, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*new_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offset.

+

+

data - A generator, an integer offset and an optional integer limit, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*union (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the union of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*union_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the union of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*union_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the union of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*union_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the union of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*sect (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the intersection of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*sect_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the intersection of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*sect_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the intersection of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*sect_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the intersection of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*symdif (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the symmetrical difference of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*symdif_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the symmetrical difference of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*symdif_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the symmetrical difference of sets integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*symdif_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the symmetrical difference of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*dif (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the difference of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*dif_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the difference of sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

*dif_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the difference of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

*dif_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the difference of sets of integers.

+

+

data - Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+


+

Instance Methods

+


+

union (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the union of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

| (...data)

+

+

Binary operator for instance method union

+

+

union_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the union of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

|* (...data)

+

+

Binary operator for instance method union_i

+


+

union_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the union of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

union_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the union of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

sect (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the intersection of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

& (...data)

+

+

Binary operator for instance method sect

+

+

sect_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the intersection of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

&* (...data)

+

+

Binary operator for instance method sect_i

+

+

sect_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the intersection of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

sect_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the intersection of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

symdif (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the symmetrical difference of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

-- (...data)

+

+

Binary operator for instance method symdif

+

+

symdif_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the symmetrical difference of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

--* (...data)

+

+

Binary operator for instance method symdif_i

+

+

symdif_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the symmetrical difference of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

symdif_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the symmetrical difference of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

dif (...data)

+

+

Creates a new Sieve object in mode 'points', generated by the difference of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

- (...data)

+

+

Binary operator for instance method dif

+

+

dif_i (...data)

+

+

Creates a new Sieve object in mode 'intervals', generated by the difference of the receiver and sets of integers.

+

+

data - Generators and an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+

-* (...data)

+

+

Binary operator for instance method dif

+

+

dif_o (...data)

+

+

Creates a new Sieve object in mode 'points' with offsets, generated by the difference of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce zero and its positive multiples.

+

If no limit is passed, returned integers might go up to default limit 65536.

+


+

dif_oi (...data)

+

+

Creates a new Sieve object in mode 'intervals' with offsets, generated by the difference of the receiver and sets of integers.

+

+

data - Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. 

+

Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself.

+

Integers and Stream/Pattern output must be strictly positive. 

+

Integers as generators produce constant intervals.

+

If no limit is passed, integer intervals might be collected up to default summation limit of 65536.

+


+


+

plot 

+

+

Plot the Sieve's list.

+


+

size 

+

+

The Sieve's list size.

+


+

toPoints 

+

+

Convert the Sieve to mode 'points' and set first point to offset.

+

+

toIntervals 

+

+

Convert the Sieve to mode 'intervals' and set offset to first point.

+

+

shift (addOffset) 

+

+

Shift the Sieve's list by integer addOffset.

+

+

>> (addOffset) 

+

+

Binary operator for instance method shift.

+

+

shiftTo (targetOffset) 

+

+

Shift the Sieve's list to integer targetOffset.

+

+

>>! (targetOffset) 

+

+

Binary operator for instance method shiftTo.

+

+

shiftToZero 

+

+

Shift the Sieve's list to offset zero.

+

+

weakCopy 

+

+

Returns a new Sieve with same list object.

+

+

copy 

+

+

Returns a new Sieve with copied list object.

+


+

copyWith (seqCollection, withCheck)

+

+

Takes over mode and offset from receiver and passes an appropriate SequenceableCollection.

+

withCheck determines if seqCollection is checked according to mode.

+

withCheck defaults to true.

+


+

copyApplyTo (operator, withCheck)

+

+

Apply operator (Symbol of method or Function) to the Sieve's list and pass the result to a new 

+

Sieve with copied mode and offset.

+

withCheck determines if result of the operation is checked according to mode.

+

withCheck default to true.

+


+

== (that)

+

+

Equality check. Sieves of different mode are equal iff the lists resulting from conversion are equal.

+


+

segmentGreaterEqual (lo)

+

+

Returns a new Sieve of mode 'points' with Integers greater than or equal lo. 

+


+

>=! (lo)

+

+

Binary operator for segmentGreaterEqual

+


+

segmentGreater (lo)

+

+

Returns a new Sieve of mode 'points' with Integers greater than lo. 

+


+

>! (lo)

+

+

Binary operator for segmentGreater

+


+

segmentLessEqual (hi)

+

+

Returns a new Sieve of mode 'points' with Integers less than or equal hi. 

+


+

<=! (hi)

+

+

Binary operator for segmentLessEqual

+


+

segmentLess (hi)

+

+

Returns a new Sieve of mode 'points' with Integers less than hi. 

+


+

<! (hi)

+

+

Binary operator for segmentLess

+


+

segmentBetweenEqual (lo, hi)

+

+

Returns a new Sieve of mode 'points' with Integers greater than or equal lo and less than or equal hi. 

+

This method is more efficient than applying segmentGreaterEqual plus segmentLessEqual.

+


+

<>=! (bounds)

+

+

Binary operator for segmentBetweenEqual.

+

bounds must be an array with lo and hi.

+


+

segmentBetween (lo, hi)

+

+

Returns a new Sieve of mode 'points' with Integers greater than lo and less than hi. 

+

This method is more efficient than applying segmentGreater plus segmentLess.

+


+

<>! (bounds)

+

+

Binary operator for segmentBetween.

+

bounds must be an array with lo and hi.

+


+

checkSymmetricPeriods 

+

+

Checks the list of a Sieve for symmetric periods and returns an array [periods, symmetries, completions],

+

where periods is the clumped list of periods, symmetries a corresponding array of Symbols and

+

completions a corresponding array of Booleans, indicating if periods are complete.

+

periods can contains Symbols 'sym', 'asym', 'quasisym' and 'identic'. 

+

See Sieves and Psieve patterns for a characterisation of these types.

+

It is assumed that the receiver has a periodic list, changes between periodic and

+

aperiodic segments are not detected, so also aperiodic prefixes of periodic lists.

+

+

checkCharacteristicPeriod

+

+

Checks the first complete period based on the data returned by checkSymmetricPeriods.

+

It returns an array [characteristicPeriod, offset, oddEven, symmetry], where

+

characteristicPeriod denotes the first complete period, offset the index at which it starts

+

in the receiver's list, oddEven one of the Symbols 'odd' and 'even' and symmetry the 

+

symmetry type as in checkSymmetricPeriods.

+

+

plotCharacteristicPeriod

+

+

Plots the characteristic period returned by checkCharacteristicPeriod.

+

+

+

+

Examples

+


+


+

// instantiation with 'new'

+


+

Sieve.new(1000)

+


+

Sieve.new(4, 20)

+


+

Sieve.new_i(4, 20)

+


+

Sieve.new_o(4, 1, 20)

+


+

Sieve.new_oi(4, 1, 20)

+


+


+


+

// instantiation with union

+

// collecting multiples resp. shifted multiples

+

// limit must be wrapped into a Ref object

+


+

Sieve.union(4, 7, `20)

+


+

Sieve.union_i(4, 7, `20)

+


+

Sieve.union_o(4, 1, 7, -1, `20)

+


+

Sieve.union_oi(4, 1, 7, -1, `20)

+


+


+


+

// instantiation with intersection

+

// collecting least common multiples (lcms) resp. shifted lcms

+


+

Sieve.sect(4, 3, `30)

+


+

Sieve.sect_i(4, 3, `30)

+


+

Sieve.sect_o(4, -1, 3, 0, `30)

+


+

Sieve.sect_oi(4, -1, 3, 0, `30)

+


+


+


+

// instantiation with symmetrical difference

+

// equals union without intersection, thus multiples without lcms

+


+

Sieve.symdif(4, 3, `30)

+


+

Sieve.symdif_i(4, 3, `30)

+


+

Sieve.symdif_o(4, -1, 3, 0, `30)

+


+

Sieve.symdif_oi(4, -1, 3, 0, `30)

+


+


+

// all take more arguments

+


+

Sieve.union(4, 5, 7, `30)

+


+

Sieve.symdif(4, 5, 7, `30)

+


+


+


+

// difference is not symmetrical, but subtrahends can be swapped

+


+

Sieve.dif(4, 3, 7, `30)

+


+

Sieve.dif(3, 4, 7, `30)

+


+

Sieve.dif(3, 7, 4, `30)

+


+


+


+

// corresponding instance methods and its binary operators

+


+

a = Sieve(4, 30);

+


+

b = Sieve(3, 30);

+


+

a.union(b)

+


+

a|b

+


+

a.union_i(b)

+


+

a|*b

+


+


+

// here first arg is offset of receiver

+


+

a.union_o(0, b, 100)

+


+

a.union_oi(0, b, 100)

+


+


+

a.sect(8)

+


+

a & 8

+


+

a.sect_i(8)

+


+

a &* 8

+


+


+

a.sect_o(1, b, 5)

+


+

a.sect_oi(1, b, 5)

+


+


+

a.symdif(b)

+


+

a -- b

+


+

a.symdif_i(b)

+


+

a --* b

+


+


+

a.dif(b)

+


+

a - b

+


+

a.dif_i(b)

+


+

a -* b

+


+


+

// For conversion, segmentation and transformation examples see Sieves and Psieve patterns

+


+


+ + diff --git a/Help/Sieves and Psieve patterns.html b/Help/Sieves and Psieve patterns.html new file mode 100755 index 0000000..49173e6 --- /dev/null +++ b/Help/Sieves and Psieve patterns.html @@ -0,0 +1,1343 @@ + + + + + + + + + + + +

Sieves and Psieve patterns list building and sequencing based on Xenakis' sieves

+


+

Part of: miSCellaneous

+


+

See also: Sieve, PSPdiv, PSVunion, PSVunion_i, PSVunion_o, PSVunion_oi, PSVsect, PSVsect_i, PSVsect_o, PSVsect_oi, PSVsymdif, PSVsymdif_i, PSVsymdif_o, PSVsymdif_oi, PSVdif, PSVdif_i, PSVdif_o, PSVdif_oi, PSVop, PSVop_i, PSVop_o, PSVop_oi 

+


+

Iannis Xenakis proposed sieves as integer-based generators for rhythms, pitches and other musical parameters. For an overview of history and implementations, including his own development in Python, see Christopher Ariza's article [3].

+


+

This SC implementation comes in two variants, with the class Sieve and Psieve patterns. Both variants include the usual sieve operations, which are based on set theory and applied to integers: union, intersection, symmetric difference and difference (complement can be defined by difference). These operations are defined for an arbitrary number of arguments as well as binary operators (Sieve). Psieve as an abstract superclass of all sieve patterns integrates sieve sequences into the pattern framework whereas Sieve is defined for calculating sieves as lists, in other words Psieve patterns are the "lazy evaluation" variant of "eager evaluation" Sieve operations. Of course you can produce sieves as lists also with Psieve patterns but for calculating very large sieves beforehand you might want to prefer Sieve, as its operations are slightly faster. For using sieves in a realtime situation the overhead of Psieve patterns will mostly be irrelevant.

+

Why sieves + patterns? Not only can the ouput of sieve calculations be used in enclosing patterns – e.g. for scaling or arbitrary mapping into the continous domain –, Sieve and Psieve patterns also accept Patterns (which must be defined to produce integers) themselves as input for sieve operations, which opens a wide field for experimentation – in the case of Psieve patterns this even allows realtime control of sieve parameters and/or sieve stream output, also the logical operations can be exchanged on the fly. In one regard this is a contradiction to Xenakis' idea of sieves as an "outside-time" structure, on the other hand Xenakis, as Roads pointed out ([4], p.168), always tended to use generative procedures very freely and this also becomes explicit, when he describes "hyperbolae" (transformations) of sieves and suggests "... transformations of the logical operations in some fashion, using the laws of logic and mathematics, or arbitrarily." ([1], p.66). Patterns involve a wide range of such possibilities and provide a comfortable interface to be applied dynamically. 

+

Psieve patterns as well as Sieves can work in two modes, regarding sieves as sequences (resp. lists) of 'intervals' with an offset, or as 'points', meaning the ascending numbers itself (the wording of 'sums' and 'differences' would also be nearby, but here 'difference' is already used for set operations, so I leaned on Xenakis' terms). For efficiency reasons only one representation of a Sieve is current at a time, the default result mode is 'points'. However all operations exist in alternative result mode variants and of course Sieves can also be converted anytime. For calculus of Sieves there exist corresponding binary operators as shortcuts.

+

Characteristics of sieves are closely bound to relations of numbers by prime factors, roughly said: more complexity and longer periodicity is following from merging moduls that have fewer prime factors in common. However for the sake of keeping classes light-weight, dealing with period lengths etc. is not implemented within the sieve classes itself. See [1] and [3] for some number-theoretical considerations, you might also want to check Xenakis' original examples and hints. Useful integer operations (prime numbers, factoring) are contained in SC main and can help you to easily carry through your own experiments, some extensions of built-in lcm-algorithm are contained (4b). A thorough investigation of the symmetric structures generated is out of the scope of this package, however some observations on symmetry types and basic analysis tools are included (3). Last but not least: plotting the intervals can give a good impression of sieve characteristics.

+


+


+

References

+


+

[1] Xenakis, Iannis (1990). “Sieves” Perspectives of New Music 28(1): 58-78.

+

[2] Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition.

+

[3] Ariza, Christopher (2005). "The Xenakis Sieve as Object: A New Model and a Complete Implementation" Computer Music Journal 29(2): 40-60.

+

[4] Roads, Curtis (2015). Composing Electronic Music. A New Aesthetic. Oxford University Press.

+


+


+

1) The Sieve class

+


+

1a) Basic generation from Integers, modes 'intervals' and 'points'

+

+

// define a simple sieve with multiples of 3, 5 and 7, 0 is included

+

// as no limit is given, the result goes up to the default limit of 65536

+

// per default result is given in mode 'points'

+


+

a = Sieve.union(3, 5, 7)

+


+


+

// a limit is passed as Ref object as last arg

+


+

a = Sieve.union(3, 5, 7, `30)

+


+


+

// convert to 'intervals': same Sieve object and new List that has one item less,

+

// the slot 'offset' is set accordingly (here it equals 0)

+

// the offset in mode 'points' is always nil

+


+

a.toIntervals

+


+


+

// convert back

+


+

a.toPoints

+


+


+

// access for arbitrary further use

+


+

a.list

+


+


+

// generate a Sieve from an Integer, it contains one point 

+


+

a = 5.toSieve.dump;

+


+

// it's interval representation is an empty list

+


+

a.toIntervals.dump

+


+


+

// calculate with 'intervals' from the beginning

+


+

Sieve.union_i(3, 5, 7, `30)

+


+


+


+

1b) Generation from Patterns, Streams and Sieves

+

+

// Instead of Integers producing their multiples you can pass Patterns or Streams.

+

// It's assumed that Patterns/Streams produce Integers interpreted as intervals

+

// (if it's defined to produce 'points' it can e.g. be wrapped into a Pdiff).

+


+

Sieve.union(Pseq([1, 10], inf), 5, 7, `30)

+


+

Sieve.union({ loop { rrand(1,10).yield } }.r, 5, 7, `30)

+


+


+

// compare with result from the pattern alone

+

// a union with one argument just returns its resulting elements.

+

// As pattern arguments are interpreted as intervals, 0 is included

+


+

Sieve.union(Pseq([1, 10], inf), `30)

+


+


+

// a Sieve can itself be passed to generate a new one,

+

// the mode of the passed sieve is taken into account

+


+

a = Sieve.union(5, 7, `30);

+


+

Sieve.union(a, 3, `30)

+


+


+


+

1c) Elementary sieve operations

+

+

// beneath union: intersection, symmetric difference, difference

+

// note that order of arguments only plays a role with difference

+


+


+

// intersection: only integers produced by all generators

+

// symmetric difference: only integers produced by one of the generators

+

// difference: only integers produced by the first generator, but by none of the others

+


+

// 'generator' here refers to allowed sieve operator args 

+

// (Integers as modul generators, Patterns/Streams or Sieves itself)

+


+


+

// proof of concept, evaluate in order

+


+

a = Sieve.union(3, 5, 6, `100)

+


+

// collect all pairwise intersections

+


+

(

+

b = Sieve.sect(3, 5, `100); // intersection with moduls: multiples of smallest common multiple

+

c = Sieve.sect(5, 6, `100);

+

d = Sieve.sect(3, 6, `100); // multiples of 6 itself

+

)

+


+

// calculate the symmetric difference ...

+


+

e = Sieve.symdif(3, 5, 6, `100)

+


+


+

// ... it equals the difference of a, b, c and d ...

+


+

f = Sieve.dif(a, b, c, d, `100)

+


+

e == f

+


+

// ... which equals the difference of a and the union of b, c and d

+


+

g = Sieve.dif(a, Sieve.union(b, c, d, `100))

+


+

e == g

+


+


+

1d) Offset methods

+

+

// for passing individual offsets there exist dedicated methods with suffixes '_o' and '_oi'

+

// offsets args are passed after the generating items

+


+


+

// one generating number with offset

+

// producing, mathematically spoken, a part of the residual class 2 modulo 3

+


+

Sieve.union_o(3, 2, `30)

+


+


+

// several generating numbers with offsets, passed pairwise

+


+

Sieve.union_o(3, 2, 5, 1, 7, 4, `30)

+


+

Sieve.union_oi(3, 2, 5, 1, 7, 4, `30)

+


+


+


+

// the shift operation adds an offset, it changes the receiver

+


+

a = Sieve.union(5, 7, `30);

+


+

a.shift(100)

+


+

a.shiftTo(0)

+


+

// as operators

+


+

a >> 100

+


+

a >>! 10

+


+


+


+

1e) Sieve operations defined as instance methods

+


+

// all operations and shortcuts defined above can be applied to instances

+


+

(

+

a = Sieve.union(3, 5, `1000);

+

b = Sieve.union(4, 7, `1000);

+

c = Sieve.union(6, 8, `1000);

+

)

+


+

// Note that large periods are already resulting from simple combinations of

+

// elementary operations and few prime factors.

+


+


+

// by default plot shows intervals

+


+

symdif(a, b, c).plot

+


+

dif(a, b, c).plot

+


+


+


+


+

1f) Sieve operations defined as binary operators

+


+

// instantiation with 'new': second arg limit doesn't need to be a Ref

+

(

+

a = Sieve(6, 60);

+

b = Sieve(8, 60);

+

)

+


+

// union

+


+

union(a,b)

+

a|b

+


+

union_i(a,b)

+

a|*b

+


+


+

// intersection

+


+

sect(a,b)

+

a&b

+


+

sect_i(a,b)

+

a&*b

+


+


+

// symmetric difference

+


+

symdif(a,b)

+

a--b

+


+

symdif_i(a,b)

+

a--*b

+


+


+

// difference, only elementary operation where order plays a role

+


+

dif(a,b)

+

a-b

+


+

dif_i(a,b)

+

a-*b

+


+

dif(b,a)

+

b-a

+


+

dif_i(b,a)

+

b-*a

+


+


+

// Efficiency hint: for an operation with a number of args, especially with large Sieves,

+

// it is more efficient to use the core class or instance methods than to concatenate binary operators:

+

// doing the latter means stepping through the list/range with each binary operation

+


+


+

1g) Segments of Sieves

+


+

// These operations result in new Sieve objects of mode 'points'

+


+

a = Sieve.union(3, 5, 7, `30)

+


+


+

// lo bound

+


+

a.segmentGreaterEqual(7)

+


+

a >=! 7

+


+

a.segmentGreater(7)

+


+

a >! 7

+


+


+

// hi bound

+


+

a.segmentLessEqual(10)

+


+

a <=! 10

+


+

a.segmentLess(10)

+


+

a <! 10

+


+


+

// lo & hi bound

+


+

a.segmentBetweenEqual(10, 20)

+


+

a <>=! [10, 20]

+


+

a.segmentBetween(10, 20)

+


+

a <>! [10, 20]

+


+


+


+

1h) Conversion to Sieves from Arrays 

+


+

// Conversion from arbitrary SequenceableCollection to Sieve:

+

// per default it's assumed that receiver and result are thought to be in mode 'points'

+

// but source and target mode can be passed as args 'fromMode' and 'toMode'

+


+

a = [1, 5, 17, 33, 37, 43, 57, 60, 61, 62, 63, 75, 89, 92, 97];

+


+

a.toSieve

+


+


+


+

// define result mode, add offset

+


+

a.toSieve(toMode: \intervals, addOffset: 100)

+


+


+

// define interval meaning of receiver

+

// default offset zero

+


+

a.toSieve(\intervals)

+


+


+

// same with offset 1, abbreviations for mode selection

+


+

a.toSieve(\i, \p, 1)

+


+


+


+

// if Integers are regarded as points, they must be ascending ...

+


+

a.reverse.toSieve

+


+


+

// ... but intervals can be descending ...

+


+

a.reverse.toSieve(\i)

+


+


+

// ... however they must be positive

+


+

(a.reverse ++ -1).toSieve(\i)

+


+


+

// It's possible to disable the checks preformed with conversion (flag 'withCheck'),

+

// but this only makes sense in a context where a large number of

+

// speed-critical conversions on well-prepared data has to be done.

+

// Otherwise it's always useful to perform those checks as

+

// sieve operations on wrong data (e.g. unordered lists) will fail or hang.

+


+


+


+

1i) Copying and transformation of Sieves by arbitrary array operations 

+


+

// It would be possible to define Sieve as subclass of List but there exist many

+

// methods for List which don't make any sense for sieves, even worse: they can consequently

+

// result in disfunctionality of standard operations defined for Sieves as List subclasses.

+

// This could be overcome with additional checks for these standard operations, a bloating which

+

// can be avoided if we try to keep only "proper sieves" as Sieve objects,

+

// thus by default dedicated wrappers for arbitrary transformations include checks.

+


+


+

a = Sieve.union_o(3, 1, 7, 2, `30)

+


+

// simple deep copy ...

+


+

b = a.copy

+


+


+

// ... lists are equal but not identical

+


+

a.list == b.list

+

a.list === b.list

+


+

// as expected sieves are equal

+


+

a == b

+


+

// but also a converted Sieve is equal

+


+

a == b.toPoints

+


+


+


+

// mode (intervals) and offset are taken over from original Sieve

+

// new array is inserted and checked if it contains proper (ascending) integers

+


+

a.copyWith([2, 17, 29, 31, 35, 53])

+


+

a.copyWith([2, 2, 3, 5, 1, 10])

+


+


+


+


+

// if the receiver is of mode 'intervals', the array of above can be passed

+


+

b = a.copy.toIntervals

+


+

b.copyWith([2, 2, 3, 5, 1, 10])

+


+


+


+

// main workhorse for transformations, note that offset is kept while intervals reversed

+


+

c = b.copyApplyTo(\reverse)

+


+

c.toPoints

+


+


+

b.copyApplyTo(\mirror).plot

+


+


+

// as with method 'applyTo' arbitrary Functions can be passed

+


+

b.copyApplyTo { |x| x * x * x ++ (1..10).mirror  }

+


+


+

// partial application

+


+

b.copyApplyTo(_ ++ [7, 5, 1])

+


+


+


+

2) Psieve patterns

+


+

2a) Basic generation from Integers, output modes 'intervals' and 'points'

+

+

// Psieve patterns use the prefix PSV followed by the name of elementary

+

// sieve operations, as used with the Sieve class, and optional suffixes.

+

// In comparison with Sieve more arguments are taken, so

+

// the generating arguments and offsets are to be passed within an array.

+


+


+

PSVunion([3, 5, 7]).asStream.nextN(20)

+


+

// intervals

+


+

PSVunion_i([3, 5, 7]).asStream.nextN(20)

+


+


+

// other operations

+


+

PSVsect([3, 5, 7]).asStream.nextN(20)

+


+

PSVsymdif([3, 5, 7]).asStream.nextN(20)

+


+

PSVdif([3, 5, 7]).asStream.nextN(20)

+


+


+


+

// offsets, offsets + interval output

+


+

PSVunion_o([3, 2, 5, 4]).asStream.nextN(20)

+


+

PSVunion_oi([3, 2, 5, 4]).asStream.nextN(20)

+


+


+

PSVdif_o([3, 2, 5, 4]).asStream.nextN(20)

+


+

PSVdif_oi([3, 2, 5, 4]).asStream.nextN(20)

+


+

...

+


+

// maxLength defines the maximum number of items -

+

// in case of a randomly generating item or a low summation limit

+

// the overall stream might have to end earlier.

+


+

b = PSVunion([7, 17, 29], 30).asStream

+


+

b.all

+


+


+

// if the summation limit is set, maxLength might not be reached

+


+

c = PSVunion([7, 17, 29], 30, 100).asStream

+


+

d = c.all

+


+

d.size

+


+


+


+

2b) Generation from Patterns, Streams and Sieves

+

+

// distorted periodicity by union with random sieve

+


+

a = ({ rrand(0, 1000) } ! 50).asSet.asArray.sort.toSieve

+


+

PSVunion_i([4, 7, a]).asStream.nextN(100).plot

+


+

// compare

+


+

PSVunion_i([4, 7]).asStream.nextN(100).plot

+


+


+


+

// distorted periodicity by union with random patterns

+


+

PSVunion_i([4, 7, Pn(Pshuf([2, 5, 9])) ]).asStream.nextN(100).plot

+


+

PSVunion_i([4, 7, Pwhite(3, 5) ]).asStream.nextN(100).plot

+


+


+


+

2c) Sequencing logical operations

+

+

// This is done by PSVop patterns, which take a Symbol or a pattern of Symbols,

+

// refering to the elementary logical operators.

+

// The stream of operations is forwarded with every integer point, 

+

// which has to be stepped through.

+


+

// helper function for plotting

+


+

p = { |x, n = 200| x.asStream.nextN(n).plot };

+


+


+

// plain standard operations, all elementary PSV patterns can be written with PSVop

+


+

PSVop([5, 9], \u).asStream.nextN(20) // union

+

PSVop([5, 9], \d).asStream.nextN(20) // difference

+

PSVop([5, 9], \sd).asStream.nextN(20) // symmetric difference

+


+


+

// some operator loops

+


+

p.(PSVop_i([5, 9], Pseq([\u, \sd], inf)))

+

p.(PSVop_i([5, 9], Pseq([\u, \s], inf)))

+

p.(PSVop_i([5, 9], Pseq([\u, \d], inf)))

+

p.(PSVop_i([5, 9], Pseq([\u, \d, \sd], inf)))

+


+


+

// random operator changes

+


+

p.(PSVop_i([5, 9], Pn(Pshuf([\u, \d]))))

+

p.(PSVop_i([5, 9], Prand([\u, \d], inf)))

+


+


+


+

// change of difIndex:

+


+

p.(PSVop_i([5, 2, 3], \d))

+

p.(PSVop_i([5, 9], Prand([\u, \d], inf)))

+


+


+

// "subtract" from index 0: multiples of 5, not divided by 7, 9, and 12

+


+

PSVdif([5, 7, 9, 12]).asStream.nextN(30)

+


+


+

// same as intervals, plotted

+


+

p.(PSVdif_i([5, 7, 9, 12]))

+


+

// written with PSVop

+


+

p.(PSVop_i([5, 7, 9, 12], \d, 0))

+


+


+

// also changing the positions other than the first is equivalent

+


+

p.(PSVdif_i([5, 7, 9, 12]))

+


+

p.(PSVop_i([5, 12, 7, 9], \d, 0))

+


+


+


+

// but "subtracting" from another number is different

+


+

p.(PSVdif_i([12, 9, 7, 5]))

+


+


+

// you can write the same with PSVop and difIndex without swapping the elements

+


+

p.(PSVop_i([5, 12, 7, 9], \d, 1))

+


+


+


+

// you can generate more complicated periods by more refined series of difIndices ...

+


+


+

p.(PSVop_i([4, 7], \d, 0))

+


+


+

p.(PSVop_i([4, 7], \d, PLseq([0, 0, 1])))

+


+

p.(PSVop_i([4, 7], \d, PLseq([0, 0, 1, 0, 0, 0, 1])))

+


+


+

// ... or combination of dynamic operator changes and difIndex changes.

+

// difIndices are only forwarded when operator 'difference' is current

+


+

p.(PSVop_i([4, 7], PLseq([\d, \d, \u]), PLseq([0, 0, 1])))

+


+


+

2d) Using Sieves in other than Psieve patterns

+


+

// Period lengths of intervals of basic Sieves are related to prime factors and 

+

// least common multiples (see Ref. [1] and [3] for a more detailled description)

+


+

// So when using intervals of those basic structures it is not necessary to 

+

// sum up to large numbers, which is what Sieve methods with suffix '_i' and

+

// corresponding Psieve patterns internally do, as they are not checking for periodicity.

+

// Instead we can calculate the list of intervals beforehand and use it at will.

+

// Also 'beforehand' doesn't exclude realtime use: it's easy to write a Function that

+

// generates Sieves and derives Patterns from it, which, with placeholder patterns,

+

// can be exchanged on the fly

+


+


+

// choose factors and calculate lcm (see 3b),

+

// as a summation limit it determines one period of intervals

+


+

a = [5, 6, 8];

+


+

m = a.lcmByGcd;

+


+

// calculate one period of intervals, plot the symmetric structure

+


+

x = Sieve.union_i(5, 6, 8, `m);

+


+

x.plot;

+


+


+

// sieve loop without counting high

+


+

Pseq(x.list, 5).asStream.all.plot

+


+


+

// second Sieve

+


+

(

+

b = [20, 17];

+

n = b.lcmByGcd;

+

v = b ++ `n;

+

y = Sieve.union_i(*v);

+

y.plot;

+

)

+


+

// make list for use with arbitrary Patterns

+


+

z = x.list ++ y.list;

+


+

z.plot;

+


+


+

// alternating sieves

+


+

Pseq(z, 3).asStream.all.plot;

+


+


+

// sequencing random segments of random length

+

// this is done with Pindex, an ascending index list of random length and a random offset

+


+

//  Function for Plazy

+


+

q = { Pindex(z, Pseq((0..rrand(10, 20))) + z.size.rand) }

+


+

Pn(Plazy(q), 30).asStream.all.plot;

+


+


+

// sequencing randomly repeated random segments of random length

+


+

q = { Pindex(z, Pseq(((0..rrand(10, 20)) ! rrand(1, 5)).flat) + z.size.rand) }

+


+

Pn(Plazy(q), 20).asStream.all.plot;

+


+


+

3) Periodicity of intervals with elementary operations

+


+

3a) Periodicity of intervals with elementary operations

+


+

// For 'union' and no offsets one period of intervals is given with summation limit

+

// equal to the least common multiple (lcm) of the generating numbers.

+

// (if one number divides another, the larger one can be dropped)

+


+

// The period length (number of intervals per period) is thus lesser than the lcm.

+

// A symmetric structure is produced, for 'union' the period is equal to its mirror, 

+

// in other words the produced sequence is a concatenation of symmetric segments

+


+

// With 3, 7 and 8 lcm equals 168

+


+

a = Sieve.union_i(3, 7, 8, `168)

+


+

a.plot

+


+

// number of intervals per period

+


+

a.size

+


+

// For symmetric difference and difference lcm also plays a role,

+

// but it's a bit different.

+

// As (offset 0) 0 is not included, the interval sequence doesn't really start from there,

+

// so  with limit = lcm the period is incomplete (although the segment is already symmetric)

+


+

Sieve.symdif_i(3, 7, 8, `168).plot

+


+


+

// To get the full picture take twice lcm as limit:

+

// the interval in the middle was not included before !

+


+

Sieve.symdif_i(3, 7, 8, `(168 * 2)).plot

+


+


+


+

// you can get the continuation to symmetry (begin = end)

+

// with a real start point as offset:

+


+

Sieve.symdif_oi(3, -3, 7, 0, 8, 0, `(168 + 3)).plot;

+


+

Sieve.dif_oi(3, -3, 7, 0, 8, 0, `(168 + 3)).plot;

+

Sieve.dif_oi(7, -7, 3, 0, 8, 0, `(168 + 7)).plot;

+

Sieve.dif_oi(8, -8, 3, 0, 7, 0, `(168 + 8)).plot;

+


+


+

// In other words in the latter cases the produced sequence is a 

+

// concatenation of symmetric segments, in which begin/end points are merged.

+


+


+

3b) Types of symmetry

+


+

// Symmetric structures in periodic series occur as different types,

+

// depending if the period length is even or odd.

+


+

// Definition: 

+

// Lets's call a period 'symmetric' iff it's equaling its reverse.

+

// Lets's call a period 'quasi-symmetric' iff the continuation with its first element is symmetric.

+


+

// If a sequence contains a symmetric or quasisymmetric period, there exists a

+

// symmetric or quasisymmetric period starting in its middle (or just right from it when odd), 

+

// let denote it its 'coperiod'.

+


+

// Statements (formal proof omitted, but rather straightforward): 

+


+

// (1) If the period length is even, a symmetric

+

// period corresponds to a symmetric coperiod and a quasisymmteric period

+

// corresponds to a quasisymmteric coperiod.

+

// (2) If the period length is odd, a symmetric

+

// period corresponds to a quasisymmteric coperiod.

+

// (3) Only a period of identic elements can be symmetric and quasi-symmetric at the same time.

+


+


+

3c) Analysis tools

+


+

// Method 'checkSymmetricPeriods' applies to Arrays resp. intervals of Sieves

+

// and checks for periods and possible symmetries.

+

// It returns an array with 4 items:

+

// (1) the sequence clumped in (quasi-)symmetric (or asymmetric) chunks

+

// (2) the index offset of the first (quasi-)symmetric period

+

// (3) a symbol indicating if the period length is even or odd

+

// (4) an array of Booleans indicating the completeness of the clumped chunks (incomplete periods can be of any type)

+


+

// Some important points here:

+

// (1) 'checkSymmetricPeriods' searches for smallest periods and its (possible) symmetry

+

// (2) 'checkSymmetricPeriods' is supposing that no prefix items are introducing

+

// a periodicity, thus a sequence like  7, 8, 9, 1, 2, 3, 2, 1, 2, 3, 2, 1 ...

+

// will be regarded as non-periodic (this e.g. happens when offsets are far apart!).

+

// (3) In the case of odd quasi-symmetric periods the symmetric coperiod is searched for

+

// and preferred (if it's in the range) 

+

// (4) To get meaningful results for sieves and its elementary operations –

+

// due to (1) and (3) – it is recommended to check sufficiently large sieves,

+

// e.g. set the limit to three times the lcm of the generators.

+


+

// make a Sieve with generating prime Integers 3, 7, 8

+

// regard a section of three time the expected period length

+


+

(

+

a = Sieve.symdif_i(3, 7, 10, `(210 * 3));

+

a.plot;

+

)

+


+

// store analysis data

+

b = a.checkSymmetricPeriods

+


+

// clumped sequence (long)

+

b[0]

+


+

// symmetry types of chunks and completions, the first relevant period is at position 1 and quasisymmetric

+

b[1..2]

+


+

// 'checkCharacteristicPeriod' returns an array with first characteristic period, 

+

// index offset, length type (even or odd) and symmetry type

+


+

a.checkCharacteristicPeriod

+


+

// you can plot it directly, compare with the sieve plot, where period starts at index 41

+


+

a.plotCharacteristicPeriod

+


+


+

3d) Symmetry types of elementary operations without offset

+


+

// Some observations of types occuring, no proof.

+

// Connections between types and used numbers are not obvious here:

+

// all symmetry types of an operator occur with tuples of coprime and not-coprime numbers

+


+

// union:

+


+

// symmetric odd period

+

(

+

a = Sieve.union_i(3, 7, `42);

+

a.plot;

+

a.plotCharacteristicPeriod;

+

)

+


+

// symmetric even period

+

(

+

a = Sieve.union_i(4, 9, `72);

+

a.plot;

+

a.plotCharacteristicPeriod;

+

)

+


+


+

// symdif:

+


+

// symmetric odd period

+

(

+

a = Sieve.symdif_i(8, 9, `216);

+

a.plot;

+

a.plotCharacteristicPeriod;

+

)

+


+

// quasi-symmetric even period

+

(

+

a = Sieve.symdif_i(7, 9, `189);

+

a.plot;

+

a.plotCharacteristicPeriod;

+

)

+


+

// dif:

+


+

// symmetric odd period

+

(

+

a = Sieve.dif_i(5, 6, `90);

+

a.plot;

+

a.plotCharacteristicPeriod;

+

)

+


+


+

// quasi-symmetric even period

+

(

+

a = Sieve.dif_i(6, 10, `90);

+

a.plot;

+

a.plotCharacteristicPeriod;

+

)

+


+


+

3e) Symmetry types of elementary operations with offset

+


+

// If generators are coprime all is quite straight: offsets will not change the

+

// sum of the period equal to the least common multiple but will only cause a shift.

+

// This was elaborated by Xenakis in [1]

+


+


+

// Things become more complicated when generators have prime factors in common:

+

// still period sums are preserved, but symmetry types can change;

+

// asymmetric periods occur. One and the same tuple of generators can cause

+

// different combinations of period types with different offsets.

+


+


+

// Here's a little helper Function to analyze characteristics of different offsets

+

// for a given choice of generating integers

+


+

(

+

f = { |operator = \union_i ...generators|

+

var sieve, types, allGens, lcm, data, input, offsets;

+

//collect all offset combinations

+

offsets = (generators.collect { |i| (0..i-1) }).allTuples;

+


+

offsets.collect { |offset|

+

lcm = lcmByGcd(*generators);

+

input = [operator] ++ [generators, offset].flop.flat ++ Ref(lcm * 4);

+

sieve = Sieve.perform(*input);

+

data = sieve.checkCharacteristicPeriod;

+

([operator, offset] ++ (data.drop(1)) ++

+

["lcm " ++ lcm.asInteger] ++ ["periodSum " ++ data.first.sum]).postln;

+

};

+

""

+

}

+

)

+


+

// this pair of generators gives three different types: odd asym, odd sym, even sym

+

f.(\union_oi, 8, 12)

+


+

// check:

+

// odd asymmetric

+

Sieve.union_oi(8, 0, 12, 1, `48).plot;

+


+

// odd symmetric

+

Sieve.union_oi(8, 0, 12, 2, `48).plot;

+


+

// even symmetric

+

Sieve.union_oi(8, 0, 12, 4, `48).plot;

+


+


+

// odd sym, even sym, even asym

+

f.(\union_oi, 12, 20)

+


+

// odd asym, even sym

+

f.(\union_oi, 15, 20)

+


+

// odd sym, even asym

+

f.(\union_oi, 9, 15)

+


+


+

// More types result from more fixed generators with varying offsets

+

// here: odd sym, odd asym, even sym, even asym

+


+

f.(\union_oi, 8, 10, 12)

+


+


+


+

// Also note that trivial genrator combinations for union without offset (when dividing each other),

+

// bring different results with offsets

+


+

// sequence of equal intervals (2)

+


+

Sieve.union_i(2, 6, 12, `48)

+


+


+

// asymmetric periods with same generators and offsets

+


+

Sieve.union_oi(2, 0, 6, 5, 12, 1, `48).plot;

+


+

// Under same assumption of generators with prime factors in common, a

+

// similar enrichment of symmetry types occurs with operators 'dif' and 'symdif'

+

// when offsets are used. In contrast to 'union' but as with 'dif' and 'symdif'

+

// without offsets, quasisymmteric periods occur.

+


+


+

// changing of symmetry types can also be done by looped sequencing of logical operations

+


+

// symmetric period produced by operator 'union'

+


+

a = PSVop_i([6, 5, 7], \u).iter.nextN(500).toSieve(\i, \i);

+


+

a.plotCharacteristicPeriod;

+


+


+

// altered, here still symmetric with logical sequence

+


+

a = PSVop_i([6, 5, 7], Pseq([\u, \d, \sd, \d], inf)).iter.nextN(500).toSieve(\i, \i);

+


+

a.plotCharacteristicPeriod;

+


+


+


+

4) Troubleshooting

+


+

4a) Critical inputs, limits

+


+

// Due to the definition of sieves there are input combinations which

+

// might result in massive looping without any result.

+


+

// Default settings are chosen in a way that this shouldn't result in hangs immediately,

+

// nevertheless it's the users's responsibility to choose meaningful input values.

+


+


+

// E.g. here we demand multiples of 3 which, at the same time, shouldn't be multiples of 3 ...

+

// The result nil is given not before the limit of 65536 is reached by summation,

+

// benchmarking indicates that.

+


+

PSVdif([3, 3], 10).asStream.next

+


+

{ PSVdif([3, 3], 10).asStream.next }.bench

+


+

Sieve.dif(3, 3)

+


+

{ Sieve.dif(3, 3) }.bench

+


+


+


+

// similar here, no intersection

+


+

PSVsect_o([3, 0, 3, 1], 10).asStream.next

+


+

{ PSVsect_o([3, 0, 3, 1], 10).asStream.next }.bench

+


+

Sieve.sect_o(3, 3)

+


+

{ Sieve.sect_o(3, 3) }.bench

+


+


+

// Another critical operation is intersection with larger coprime numbers

+


+

nthPrime(70)

+

-> 353

+


+

nthPrime(71)

+

-> 359

+


+


+

a = PSVsect([353, 359]).asStream;

+


+

// first intersection at 0, but no further one (below global limit 65536)

+


+

a.nextN(2)

+


+


+

// you can set the limit, but it's a rather inefficient way to 

+

// generate just a series of equal intervals ... 

+


+

a = PSVsect([353, 359], limit: 2 ** 30).asStream;

+


+

a.nextN(20)

+


+

{ a.nextN(20) }.bench

+


+


+

// The largest Integer with 32 bit is 2 ** 31 - 1.

+

// You can set 'limit' with Sieves and Psieve patterns (for instances and globally)

+

// up to 2 ** 31 - 1 - maxGeneratingInteger.

+

// This ensures that the threshold check doesn't exceed the Integer range.

+


+


+

// So if you're sure about useful inputs

+

// you can set a high global limit for calculus with large numbers and/or long streams

+


+

Psieve.limit = 2 ** 31 - 536892

+


+

{ a = PSVunion([253630, 536891]).asStream.nextN(10000) }.bench

+


+


+

// reset global limit

+


+

Psieve.limit = 65536

+


+


+

// Note that Psieve is a bit more flexible as Sieve in this regard

+

// it allows to set summation limit and maxLength.

+


+

Sieve.limit = 2 ** 31 - 536892

+


+

{ a = Sieve.union(253630, 536891) }.bench

+


+

a.list.size

+


+


+

// reset global limit

+


+

Sieve.limit = 65536

+


+


+


+

4b) Calculating least common multiples

+


+

// For calculating period lengths the related operations of greatest common divisor

+

// and least common multiple are relevant (e.g. see Ref. [1])

+


+

// Up to SC 3.7.2 built-in method 'lcm' fails for large Integers,

+

// though this has been fixed in 3.8:

+


+

lcm(248214, 1027542)

+


+

-> 6696095

+


+


+

// A prime factor analysis shows:

+


+


+

a = [248214, 1027542].collect(_.factors)

+


+

-> [ [ 2, 3, 41, 1009 ], [ 2, 3, 41, 4177 ] ]

+


+


+

// Thus the result would have to be

+


+

2.0 * 3 * 41 * 1009 * 4177

+


+

-> 1036789878

+


+


+

// Why is 2.0 needed above ? 

+

// The result of an Integer multiplication is an Integer, 

+

// thus crossing the int32 limit is silent and can easily be overlooked

+


+

3768562 * 876876

+


+

-> 1731721688

+


+


+

3768562.0 * 876876

+


+

-> 3304561572312

+


+


+

// The methods lcmByFactors and lcmByGcd contain the relevant threshold checkes,

+

// they are much slower than 'lcm' but reliable also with large Integers.

+

// 'lcmByFactors' returns an array with lcm as first item, an array with prime factors

+

// of lcm as second item and an array of receiver's and all arguments' prime factors. 

+

// Alternatively the least common multiple can be calculated 

+

// via the greatest common divisor, this is done by method 'lcmByGcd'

+


+

lcmByFactors(248214, 1027542)

+

lcmByGcd(248214, 1027542)

+


+


+

// if calculation exceeds the int32 limit a warning is given, the result is a float

+


+

lcmByFactors(135630546, 429496729)

+

lcmByGcd(135630546, 429496729)

+


+


+

// also more args can be passed (all are integers < 2 * 31),

+

// as lcmByGcd uses gcd internally, this might fail with more than 2

+

// large numbers, whereas lcmByFactors still finds the result

+


+

lcmByGcd(135630546, 429496729, 610337457)

+

lcmByFactors(135630546, 429496729, 610337457)

+


+


+

5) Audio examples

+


+

// synthdefs to play with

+


+

(

+

SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1|

+

var sig = { WhiteNoise.ar } ! 2;

+

sig = BPF.ar(sig, freq, rq) *

+

EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) *

+

(rq ** -1) * (250 / (freq ** 0.8));

+

OffsetOut.ar(out, sig);

+

}).add;

+


+

SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2;

+

sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

OffsetOut.ar(out, sig);

+

}).add;

+


+


+

SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1|

+

var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2;

+

sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2);

+

OffsetOut.ar(out, sig);

+

}).add;

+

)

+


+

5a) Applying sieve intervals to (micro) rhythms

+


+

(

+

// rhythm by sieve intervals

+


+

~delta = 0.05;

+

~rhy = PSVunion_i([4, 6, 7]);

+


+

p = Pbind(

+

    \instrument, \noise_grain,

+

    \dur, PL(\rhy) * PL(\delta),

+

    \att, 0.01,

+

    \rel, 0.05,

+

    \amp, 0.1,

+

    \midinote, Pwhite(50, 90),

+

    \rq, 0.1

+

).play

+

)

+


+


+

// change to micro rhythms

+


+

(

+

~delta = 0.01;

+

~rhy = PSVsymdif_i([4, 6]);

+

)

+


+

// test with different data

+


+

~rhy = PSVsymdif_i([4, 6, 9])

+


+

~rhy = PSVsymdif_i([6, 9, 2])

+


+

~rhy = PSVsymdif_i([9, 2])

+


+

~rhy = PSVsymdif_i([3, 4])

+


+

~rhy = PSVsymdif_i([3, 4, 7])

+


+


+

p.stop

+


+


+

5b) Sequentially generating new sieve patterns for rhythm and pitch

+


+

(

+

// rhythm by sieve intervals

+


+

~delta = 0.1;

+

~rhy = PSVunion_i([4, 6, 7]);

+


+

// some more params for live change

+


+

~rel = 0.05;

+

~midi = Pwhite(50, 90);

+

~rq = 0.1;

+


+

q = Pbind(

+

    \instrument, Prand([\noise_grain, \sin_grain], inf),

+

    \dur, PL(\rhy) * PL(\delta),

+

    \att, 0.005,

+

    \rel, PL(\rel),

+

    \amp, 0.1,

+

    \midinote, PL(\midi),

+

    \rq, PL(\rq)

+

).play

+

)

+


+


+

// turn to micro rhythm

+

(

+

~delta = 0.01;

+


+

// instead of Pn + Plazy also Pspawner with method .seq could be used

+

~rhy = Pn(Plazy {

+

    var r = { rrand(2, 30) } ! 2;

+

    "rhythm generators: ".post; r.sort.postln;

+

    PSVsymdif_i(r, rrand(20, 30))

+

});

+


+

// numbers generated by PSVsymdif_i are used above and below a central pitch

+

~midi = Pn(Plazy {

+

    var r = { rrand(2, 10) } ! 2;

+

    "pitch generators: ".post; r.sort.postln;

+

    PSVsymdif_i(r, rrand(10, 20)) * PLseq([1, -1]) + rrand(50, 95)

+

});

+


+


+

// sequencing rq and release time

+

~rq = Pstutter(Pwhite(2, 5), PLseq([0.005, 0.01, 0.1]));

+


+

~rel = Pstutter(Pwhite(2, 5), Pn(Pshuf([0.05, 0.1, 0.2])));

+

)

+


+

q.stop;

+


+


+

5c) Sequencing instrumental variation with sieves

+


+

// start with sin grains

+

(

+

~delta = 0.15;

+

~rhy = 1;

+

~rel = 0.04;

+

~midi = 70;

+

~instrument = \sin_grain;

+

~rq = 0.01;

+

~amp = 0.1;

+

~type = \note;

+


+

r = Pbind(

+

    \instrument, PL(\instrument),

+

    \dur, PL(\rhy) * PL(\delta),

+

    \att, 0.015 * Pwhite(0.8, 1.2),

+

    \rel, PL(\rel),

+

    \amp, PL(\amp),

+

    \midinote, PL(\midi),

+

    \rq, PL(\rq),

+

    \type, PL(\type)

+

).play

+

)

+


+

// define variation with sieve

+

(

+

~instrument = Pstutter(

+

    PSVunion_i([5, 7, 13]),

+

    PLseq([\saw_grain, \noise_grain, \sin_grain, \noise_grain])

+

)

+

)

+


+

// pitch sequence based on sieve

+

(

+

~midi = Pstutter(Pwhite(2, 5), PSVunion_i([10, 8, 17])) * PLseq([1, -1]) + 80;

+

~rel = 0.45;

+

~amp = 0.06;

+

)

+


+

// transpositions

+

(

+

~midi = Pstutter(Pwhite(2, 5), PSVunion_i([10, 8, 17])) * PLseq([1, -1]) +

+

    80 + Pstutter(Pwhite(10, 20), Pwhite(-5, 5));

+

)

+


+

// microtonal transpositions and added fifths

+

(

+

~midi = Pstutter(Pwhite(2, 5), PSVunion_i([10, 8, 17])) * PLseq([1, -1]) + 80 +

+

    Pstutter(Pwhite(10, 20), Pwhite(-10.0, 5)) +

+

    Prand([0, [0, 7]], inf);

+

)

+


+

// interfering curves generated by 'union'

+

(

+

~midi = [55, 62] + PSVunion_oi([55, 0, 57, 1, 58, 2, 59, 3]);

+


+

~rel = Pstutter(Pwhite(2, 5), Pn(Pshuf([0.05, 0.05, 0.1, 0.5])));

+

)

+


+

r.stop

+


+


+ + diff --git a/Help/Smooth Clipping and Folding.html b/Help/Smooth Clipping and Folding.html new file mode 100755 index 0000000..8ba6788 --- /dev/null +++ b/Help/Smooth Clipping and Folding.html @@ -0,0 +1,229 @@ + + + + + + + + + + + +

Smooth Clipping and Folding a suite of pseudo ugens for smooth clipping and folding

+


+

Part of: miSCellaneous

+


+

See also: SmoothClipS, SmoothClipQ, SmoothFoldS, SmoothFoldQ, SmoothFoldS2, SmoothFoldQ2 

+


+


+

Wave folding is a synthesis technique from analog days, going back to Donald Buchla and the tradition of west coast synthesis. Smooth clipping and folding pseudo ugens from miSCellaneous lib come in variants which include quadratic and sinusoidal waveshaping and allow clipping and folding without aliasing. This can also be used for buffer scratching – a synthesis technique which I have been experimenting with recently with great fun.

+


+


+

Ex. 1: Different types of folding

+

+

// A typical usage is preamplifying a signal, here we start with a sine wave, compare plots

+


+

{

+

[

+

// just smooth clipping

+

SmoothClipS.ar(SinOsc.ar(50) * 10), 

+

+

// folding with main lib's Fold ugen

+

Fold.ar(SinOsc.ar(50) * 10, -1, 1), 

+

+

// folding with rather low smoothing 

+

// wave shaper is partiallly a sine wave

+

SmoothFoldS.ar(SinOsc.ar(50) * 10, smoothAmount: 0.3), 

+

+

// folding with maximum smoothing 

+

// wave shaper is full sine wave

+

SmoothFoldS.ar(SinOsc.ar(50) * 10, smoothAmount: 1), 

+

+

// wave is folded back only to border ranges

+

SmoothFoldS.ar(SinOsc.ar(50) * 10, foldRange: 0.3),

+


+

// folding with different sizes of border ranges

+

SmoothFoldS2.ar(SinOsc.ar(50) * 10, foldRangeLo: 0.5, foldRangeHi: 0.2)

+

]

+

}.plot(1/50)

+


+


+

attachments/Smooth Clipping and Folding/fold_examples.png

+


+


+

Ex. 2: Generating rich spectra by folding sine waves

+

+

// Folding ugens do multichannel expansion, let two anticyclic sines control the fold range,

+

// control smoothing amount with MouseX

+


+

(

+

x = {

+

var source = SinOsc.ar(50);

+

SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1), MouseX.kr(0, 1))

+

}.scope

+

)

+


+

x.release

+


+


+

// Compare with the parabolic smoothing variant, the difference isn't great in this case

+


+

(

+

x = {

+

var source = SinOsc.ar(50);

+

SmoothFoldQ.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1), MouseX.kr(0, 1))

+

}.scope

+

)

+


+

x.release

+


+


+

// slow modulations of source frequency with independant LFOs 

+


+

(

+

x = {

+

var source = SinOsc.ar(50 * { LFDNoise3.kr(0.1).range(0.98, 1.02) } ! 2);

+

SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1))

+

}.scope

+

)

+


+

x.release

+


+


+

// Adding more complexity by applying preamplification (causes more folding) and adding an offset,

+

// these operations are also L/R-independant 

+


+

(

+

x = {

+

var source = SinOsc.ar(

+

50 * { LFDNoise3.kr(0.1).range(0.98, 1.02) } ! 2,

+

0,

+

{ LFDNoise3.kr(0.15).range(0.5, 3) } ! 2,

+

{ LFDNoise3.kr(0.2).range(-2, 2) } ! 2

+

);

+

SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1))

+

}.scope

+

)

+


+

x.release

+


+


+


+

Ex. 3: Applying modulated folding to LFO sources

+

+

// the other way round, take a lfo source and modulate folding parameters, here the relative folding range

+


+

(

+

x = {

+

var source = LFDNoise3.ar(0.3!2).range(0.5, 1);

+

SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.ar([50, 50.1]).range(0.1, 1) )

+

}.scope

+

)

+


+

x.release

+


+


+

// modulating fold bounds

+


+

(

+

x = {

+

var source = LFDNoise3.ar(0.3!2).range(0.5, 1);

+

var bounds = SinOsc.ar([50, 50.1]).range(0.02, 0.1);

+

SmoothFoldS.ar(source, bounds.neg, bounds)

+

}.scope

+

)

+


+

x.release

+


+


+

// modulating bounds and range

+


+

(

+

x = {

+

var source = LFDNoise3.ar(0.3!2).range(0.5, 1);

+

var range = SinOsc.ar([50, 50.1]).range(0.02, 0.1);

+

SmoothFoldS.ar(source, range.neg, range, SinOsc.ar([200, 200.1]).range(0.5, 1))

+

}.scope

+

)

+


+

x.release

+


+


+


+

Ex. 4: Buffer scratching with folded signal as position control

+

+

// Interesting micro textures can be generated that way.

+

// Technically this is waveshaping with an audio buffer as transfer function and the folded signal as source.

+


+

// compare with granulation, sound file from buffer granulation tutorial

+


+

b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

+

// This searches the most likely extension places for the miSCellaneous folder.

+

// In case of an extraordinary install situation or a removed sound file, pass the concerned path.

+


+


+

(

+

SynthDef(\bufScratchFold, { |bufnum = 0, globalFreq = 0.7, localOscSize = 0.01, foldRange = 0.28,

+

localFreq = 0.87, preAmp = 1.4, smoothAmount = 0.36|

+

var sig = BufRd.ar(

+

1,

+

bufnum,

+

(

+

// define global and local movement

+

LFDNoise3.ar(globalFreq).range(0.2, 0.7) +

+

SmoothFoldS.ar(

+

// adding space by decorrelating the local scratching / oscillation

+

LFTri.ar(localFreq * ({ LFDNoise3.ar(0.2).range(0.999, 1.001) } ! 2)) * preAmp,

+

foldRange: foldRange,

+

smoothAmount: smoothAmount

+

) * localOscSize

+

) * BufFrames.ir(bufnum)

+

);

+

// as local oscillation can stick with positive or negative values, a dc leaker is recommended 

+

Out.ar(0, LeakDC.ar(sig) * EnvGate.new)

+

}).add

+

)

+


+

x = Synth(\bufScratchFold, [bufnum: b])

+


+

x.set(\preAmp, 5.4)

+

x.set(\foldRange, 0.08)

+

x.set(\localFreq, 0.5)

+

x.set(\localOscSize, 0.05)

+

x.set(\foldRange, 0.02)

+

x.set(\localFreq, 0.1)

+


+

x.release

+


+


+


+


+


+ + diff --git a/Help/SmoothClipQ.html b/Help/SmoothClipQ.html new file mode 100755 index 0000000..b7de51b --- /dev/null +++ b/Help/SmoothClipQ.html @@ -0,0 +1,73 @@ + + + + + + + + + + + +

SmoothClipQ wave shaping / clipping pseudo ugen using parabolic segments

+


+

Part of: miSCellaneous

+


+

Wave shaping with parabolic segments at borders. The amount of smoothness can be controlled: 0 means a linear transfer function, 1 a full parabolic segment, values inbetween a transfer function which consists of a line and a parabolic segment. For amount > 0 the slope of the transfer function equals 0 at the borders.

+


+


+

See also: Smooth Clipping and Folding, SmoothClipS, SmoothFoldS, SmoothFoldQ, SmoothFoldS2, SmoothFoldQ2 

+


+


+

Class Methods

+


+

*ar (in, lo, hi, amount, delta)

+

+

*kr (in, lo, hi, amount, delta)

+

+

in - input signal.

+

lo - lower limit, defaults to -1.

+

hi - upper limit, defaults to 1.

+

amount - amount of smoothness, must be >= 0 and <= 1, defaults to 0.5.

+

delta - threshold for avoiding zero divisions (which would happen if lo = hi and the border case of amount = 1).

+

Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// control smoothness

+


+

x = { SmoothClipQ.ar(LFTri.ar(300, 0, 0.25), -0.2, 0.2, MouseX.kr(0, 1)) }.scope  

+


+

x.release

+


+


+ + diff --git a/Help/SmoothClipS.html b/Help/SmoothClipS.html new file mode 100755 index 0000000..8b20917 --- /dev/null +++ b/Help/SmoothClipS.html @@ -0,0 +1,72 @@ + + + + + + + + + + + +

SmoothClipS wave shaping / clipping pseudo ugen using sine segments

+


+

Part of: miSCellaneous

+


+

Wave shaping with sine segments at borders. The amount of smoothness can be controlled: 0 means a linear transfer function, 1 a full sine segment, values inbetween a transfer function which consists of a line and a sine segment. For amount > 0 the slope of the transfer function equals 0 at the borders.

+


+

See also: Smooth Clipping and Folding, SmoothClipQ, SmoothFoldS, SmoothFoldQ, SmoothFoldS2, SmoothFoldQ2 

+


+


+

Class Methods

+


+

*ar (in, lo, hi, amount, delta)

+

+

*kr (in, lo, hi, amount, delta)

+

+

in - input signal.

+

lo - lower limit, defaults to -1.

+

hi - upper limit, defaults to 1.

+

amount - amount of smoothness, must be >= 0 and <= 1, defaults to 0.5.

+

delta - threshold for avoiding zero divisions (which would happen if lo = hi and the border case of amount = 1).

+

Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// control smoothness

+


+

x = { SmoothClipS.ar(LFTri.ar(300, 0, 0.25), -0.2, 0.2, MouseX.kr(0, 1)) }.scope  

+


+

x.release

+


+


+ + diff --git a/Help/SmoothFoldQ.html b/Help/SmoothFoldQ.html new file mode 100755 index 0000000..4fcfb40 --- /dev/null +++ b/Help/SmoothFoldQ.html @@ -0,0 +1,75 @@ + + + + + + + + + + + +

SmoothFoldQ wave folding pseudo ugen using parabolic segments

+


+

Part of: miSCellaneous

+


+

Wave folding using SmoothClipQ. Values outside the range lo-hi are folded back, if foldRange > 0. A larger foldRange means less folding whereas a smaller foldRange causes more folding. The spectral result depends on the source wave form also but in general a smaller foldRange causes more energy in the higher spectrum whereas near foldRange == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced.

+


+

See also: Smooth Clipping and Folding, SmoothClipS, SmoothClipQ, SmoothFoldS, SmoothFoldS2, SmoothFoldQ2 

+


+


+

Class Methods

+


+

*ar (in, lo, hi, foldRange, smoothAmount, delta)

+

+

*kr (in, lo, hi, foldRange, smoothAmount, delta)

+

+

in - input signal.

+

lo - lower limit, defaults to -1.

+

hi - upper limit, defaults to 1.

+

foldRange - the relative amount of the range (defined by lo and hi) used for folding, should be >= 0 and <= 1. 

+

0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine 

+

the ranges near both borders, which are used for folding, defaults to 1.

+

smoothAmount - amount of smoothness, must be >= 0 and <= 1, defaults to 0.5.

+

delta - threshold for avoiding zero divisions (which would happen if lo = hi and the border case of amount = 1).

+

Normally not to be set by the user, except for very small folding ranges, defaults to 0.00001.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// see scope, MouseX controls foldRange, MouseY smoothAmount

+


+

x = { SmoothFoldQ.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0.2, 0.8), MouseY.kr(0, 1)) }.scope  

+


+

x.release

+


+


+ + diff --git a/Help/SmoothFoldQ2.html b/Help/SmoothFoldQ2.html new file mode 100755 index 0000000..21d2daa --- /dev/null +++ b/Help/SmoothFoldQ2.html @@ -0,0 +1,79 @@ + + + + + + + + + + + +

SmoothFoldQ2 wave folding pseudo ugen using parabolic segments, two fold ranges

+


+

Part of: miSCellaneous

+


+

Wave folding using SmoothClipQ. Values outside the range lo-hi are folded back, if the concerned foldRange > 0. A larger foldRange means less folding whereas a smaller foldRange causes more folding. The spectral result depends on the source wave form also but in general a smaller foldRange causes more energy in the higher spectrum whereas near foldRange == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced.

+


+

See also: Smooth Clipping and Folding, SmoothClipS, SmoothClipQ, SmoothFoldS, SmoothFoldQ, SmoothFoldS2 

+


+


+

Class Methods

+


+

*ar (in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta)

+

+

*kr (in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta)

+

+

in - input signal.

+

lo - lower limit, defaults to -1.

+

hi - upper limit, defaults to 1.

+

foldRangeLo - the relative amount of the range (defined by lo and hi) used for folding back values below lo, should be >= 0 and <= 1. 

+

0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine 

+

the range near lo, which is used for folding, defaults to 1.

+

foldRangeHi - the relative amount of the range (defined by lo and hi) used for folding back values above hi, should be >= 0 and <= 1. 

+

0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine 

+

the range near hi, which is used for folding, defaults to 1.

+

smoothAmount - amount of smoothness, must be >= 0 and <= 1, defaults to 0.5.

+

delta - threshold for avoiding zero divisions (which would happen if lo = hi and the border case of amount = 1).

+

Normally not to be set by the user, except for very small folding ranges, defaults to 0.00001.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// see scope, MouseX controls foldRangeLo, MouseY foldRangeHi

+


+

x = { SmoothFoldQ2.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0, 1), MouseY.kr(0, 1)) }.scope  

+


+

x.release

+


+


+


+ + diff --git a/Help/SmoothFoldS.html b/Help/SmoothFoldS.html new file mode 100755 index 0000000..7253c93 --- /dev/null +++ b/Help/SmoothFoldS.html @@ -0,0 +1,77 @@ + + + + + + + + + + + +

SmoothFoldS wave folding pseudo ugen using sine segments

+


+

Part of: miSCellaneous

+


+

Wave folding using SmoothClipS. Values outside the range lo-hi are folded back, if foldRange > 0. A larger foldRange means less folding whereas a smaller foldRange causes more folding. The spectral result depends on the source wave form also but in general a smaller foldRange causes more energy in the higher spectrum whereas near foldRange == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced.

+


+


+

See also: Smooth Clipping and Folding, SmoothClipS, SmoothClipQ, SmoothFoldQ, SmoothFoldS2, SmoothFoldQ2 

+


+


+

Class Methods

+


+

*ar (in, lo, hi, foldRange, smoothAmount, delta)

+

+

*kr (in, lo, hi, foldRange, smoothAmount, delta)

+

+

in - input signal.

+

lo - lower limit, defaults to -1.

+

hi - upper limit, defaults to 1.

+

foldRange - the relative amount of the range (defined by lo and hi) used for folding, should be >= 0 and <= 1. 

+

0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine 

+

the ranges near both borders, which are used for folding, defaults to 1.

+

smoothAmount - amount of smoothness, must be >= 0 and <= 1, defaults to 0.5.

+

delta - threshold for avoiding zero divisions (which would happen if lo = hi and the border case of amount = 1).

+

Normally not to be set by the user, except for very small folding ranges, defaults to 0.00001.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// see scope, MouseX controls foldRange, MouseY smoothAmount

+


+

x = { SmoothFoldS.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0.2, 0.8), MouseY.kr(0, 1)) }.scope  

+


+

x.release

+


+


+


+ + diff --git a/Help/SmoothFoldS2.html b/Help/SmoothFoldS2.html new file mode 100755 index 0000000..811033f --- /dev/null +++ b/Help/SmoothFoldS2.html @@ -0,0 +1,80 @@ + + + + + + + + + + + +

SmoothFoldS2 wave folding pseudo ugen using sine segments, two fold ranges

+


+

Part of: miSCellaneous

+


+

Wave folding using SmoothClipS. Values outside the range lo-hi are folded back, if the concerned foldRange > 0. A larger foldRange means less folding whereas a smaller foldRange causes more folding. The spectral result depends on the source wave form also but in general a smaller foldRange causes more energy in the higher spectrum whereas near foldRange == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced.

+


+


+

See also: Smooth Clipping and Folding, SmoothClipS, SmoothClipQ, SmoothFoldS, SmoothFoldQ, SmoothFoldQ2 

+


+


+

Class Methods

+


+

*ar (in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta)

+

+

*kr (in, lo, hi, foldRangeLo, foldRangeHi, smoothAmount, delta)

+

+

in - input signal.

+

lo - lower limit, defaults to -1.

+

hi - upper limit, defaults to 1.

+

foldRangeLo - the relative amount of the range (defined by lo and hi) used for folding back values below lo, should be >= 0 and <= 1. 

+

0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine 

+

the range near lo, which is used for folding, defaults to 1.

+

foldRangeHi - the relative amount of the range (defined by lo and hi) used for folding back values above hi, should be >= 0 and <= 1. 

+

0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine 

+

the range near hi, which is used for folding, defaults to 1.

+

smoothAmount - amount of smoothness, must be >= 0 and <= 1, defaults to 0.5.

+

delta - threshold for avoiding zero divisions (which would happen if lo = hi and the border case of amount = 1).

+

Normally not to be set by the user, except for very small folding ranges, defaults to 0.00001.

+

+


+

Examples

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

// see scope, MouseX controls foldRangeLo, MouseY foldRangeHi

+


+

x = { SmoothFoldS2.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0, 1), MouseY.kr(0, 1)) }.scope  

+


+

x.release

+


+


+


+ + diff --git a/Help/TZeroXBufRd.html b/Help/TZeroXBufRd.html new file mode 100755 index 0000000..5ccbd16 --- /dev/null +++ b/Help/TZeroXBufRd.html @@ -0,0 +1,734 @@ + + + + + + + + + + + +

TZeroXBufRd triggers sequences of segments between zero crossings from one or more buffers with demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

TZeroXBufRd is for triggering possibly overlapped segments between zero crossings (half wavesets) from one or more buffers, whereby several reading and processing parameters can be sequenced with demand rate ugens. Full waveset sequences can so be generated as a special case. It needs analysis data prepared with ZeroXBufWr. For consecutive reading of segments between zero crossings see ZeroXBufRd. ZeroXBufRd / TZeroXBufRd can be used for a number of synthesis / processing techniques in a field between wavesets [1, 4, 5], pulsar synthesis [1, 3], buffer modulation and rectification (which are both a kind of waveshaping) and stochastic concatenation methods [2, 6]. There are already existing SC waveset implementations like Alberto de Campo's Wavesets quark (https://github.com/supercollider-quarks/quarks) and Olaf Hochherz's SPList (https://github.com/olafklingt/SPList), which do language-side analysis and Fabian Seidl's RTWaveSets plugin (https://github.com/tai-studio/RTWaveSets). My focus has been server-side analysis and demand rate ugen control of half waveset parameters as well as multichannel and buffer switch options. Realtime control while analysis is possible, as long as reading is only refering to already analysed sections, but clearly most flexibility is given with a fully analysed buffer, which can also be done in quasi realtime.

+


+

NOTE: Depending on the multichannel sizes and the options used (rate and dir sequencing) it might be necessary to increase server resources, i.e. the number of interconnect buffers and / or memory size (e.g. s.options.numWireBufs = 256; s.options.memSize = 8192 * 32; s.reboot). Because of overlappings this is more relevant with TZeroXBufRd than with ZeroXBufRd.

+


+

NOTE: Often it pays to adjust zero crossings in the sound buffer effectively to 0, that way sawtooth-like interpolation artefacts can be avoided. See Ex.1 below.

+


+

NOTE: Demand rate UGens in ZeroXBufRd / TZeroXBufRd must always use inf as repeats arg, this is of course not necessary for nested ones. You might pass a length arg though (Ex. 5).

+


+

NOTE: The distance between triggers must remain above control duration, otherwise the synthesis fails. For faster trigerring you'd have to use the server with a lower blocksize.

+


+

NOTE: As triggered half wavesets can overlap you'd have to care for a sufficiently large 'overlapSize' arg. See Ex.3 for possible estimations.

+


+

NOTE: For avoiding too long half wavesets it might be useful to apply LeakDC resp. a high pass filter before analysis.

+


+

NOTE: In rare cases I noticed corrupted buffers in multi buffer examples for no obvious reason.

+


+


+

CREDITS: Thanks to Tommaso Settimi for an inspiring discussion, which gave me a nudge to tackle these classes. 

+


+


+

REFERENCES:

+


+

[1] de Campo, Alberto. "Microsound" In: Wilson, S., Cottle, D. and Collins, N. (eds). 2011. 

+

The SuperCollider Book. Cambridge, MA: MIT Press, 463-504.

+

+

[2] Luque, Sergio (2006). Stochastic Synthesis, Origins and Extensions. Institute of Sonology, Royal Conservatory, The Netherlands. 

+

http://sergioluque.com

+


+

[3] Roads, Curtis (2001). Microsound. Cambridge, MA: MIT Press.

+

+

[4] Seidl, Fabian (2016). Granularsynthese mit Wavesets für Live-Anwendungen. Master Thesis, TU Berlin.

+

https://www2.ak.tu-berlin.de/~akgroup/ak_pub/abschlussarbeiten/2016/Seidl_MasA.pdf

+


+

[5] Wishart, Trevor (1994). Audible Design. York: Orpheus The Pantomime Ltd. 

+


+

[6] Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition.

+


+


+


+

See also: ZeroXBufRd, ZeroXBufWr, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies

+


+


+

Creation / Class Methods

+


+

*ar (sndBuf, zeroXBuf, bufMix, trig, zeroX = 0, xNum = 1, xRep = 1,  power = 1, mul = 1, add = 0, rate = 1, dir = 1, 

+

interpl = 4, overlapSize = 10, length = inf, maxTime = inf, att = 0, rel = 1, curve = -4, doneAction = 0)

+

+

sndBuf - Buffer or SequenceableCollection of Buffers to read the data from, data must correspond to zeroXBuf.

+

zeroXBuf - Analysis Buffer resp. SequenceableCollection of such, prepared with ZeroXBufWr. 

+

Must refer to data passed to sndBuf.

+

bufMix - A Number indicating the sndBuf index, a demand rate or other ugens returning sndBuf indices or 

+

a SequenceableCollection of such.

+

If bufMix equals nil (default) the size of the returned signal equals the size of sndBuf,

+

otherwise it equals its own size.

+

trig - A trigger signal for starting new half waveset groups.

+

zeroX - A Number indicating the index in zeroXBuf, a demand rate or other ugens returning zeroXBuf indices or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of zeroX

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 0.

+

xNum - Determining the number of half wavesets starting at zeroX, a demand rate or other ugens returning these numbers or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of xNum

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1.

+

xRep - Determining the number of repetitions of half wavesets resp. half waveset groups (given by xNum) starting at zeroX, 

+

a demand rate or other ugens returning these numbers or a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of xNum

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1.

+

power - Used for processing the buffer signal according to the formula: sig ** power * mul + add per half waveset group. 

+

Must be a positive Number, a demand rate or other ugens returning power values or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1.

+

mul - Used for processing the buffer signal according to the formula: sig ** power * mul + add per half waveset group. 

+

Must be a Number, a demand rate or other ugens returning mul values or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of mul

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1. 

+

add - Used for processing the buffer signal according to the formula: sig ** power * mul + add per half waveset group. 

+

Must be a Number, a demand rate or other ugens returning add values or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of add

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 0. 

+

rate - Determines the playback rate per half waveset group. 

+

Must be a positive Number, a demand rate or other ugens returning rate values or a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of rate

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1.

+

dir - Determines the playback direction of half waveset groups. 

+

Must be +1 or -1, a demand rate or other ugens returning dir values or a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of dir

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1. 

+

interpl - Determines the interpolation type for the BufRd ugens. 

+

Must equal 1 (no), 2 (linear) or 4 (cubic) or a SequenceableCollection of these numbers.

+

Defaults to 4. 

+

overlapSize - Determines the maximum overlap of half waveset groups. 

+

This is a fixed number or a SequenceableCollection thereof determining the size of internally used

+

multichannel signals for overlappings. If this number is too low the synthesis fails.

+

See Ex. 3 for estimating a sufficiently large value.

+

Defaults to 10. 

+

length - Determines the number of triggers before release of the overall asr envelope. 

+

Can be a Sequenceable Collection too. Overruled by maxTime if this is reached before.

+

Defaults to inf. 

+

maxTime - Determines the time before release of the overall asr envelope. 

+

Can be a Sequenceable Collection too. Overruled by length if this is reached before.

+

Defaults to inf. 

+

att - Attack time of overall asr envelope or SequenceableCollection thereof. 

+

Defaults to 0. 

+

rel - Release time of overall asr envelope or SequenceableCollection thereof.  

+

Defaults to 0. 

+

curve - Curve of overall asr envelope or SequenceableCollection thereof.  

+

Defaults to -4. 

+

doneAction - Done action of overall asr envelope or SequenceableCollection thereof.  

+

Defaults to 0. 

+

+

+


+

Examples

+


+

// See also the examples of ZeroXBufRd help. Most features work in the same way,

+

// this help file focusses rather on the differences.

+


+


+

Ex.1) Basic usage

+

+

// prepare two short buffers for audio and zero crossing data

+

// the size of needed zeroX data space can be roughly estimated

+


+

(

+

b = Buffer.alloc(s, 256);

+

z = Buffer.alloc(s, 32);

+

)

+


+

// analyse a short snippet of modulation

+


+

(

+

x = {

+

var src = SinOsc.ar(SinOsc.ar(1200, 0, 1000, 100)) * SinOsc.ar(700) - 0.1;

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+


+

// check the waveform

+


+

b.plot

+


+


+


+

// It's important to note that the maximum trigger rate should be below control rate,

+

// otherwise sequencing with demand rate ugens is messed up.

+

// This limitation can be circumvented by rebooting the server with a lower blockSize.

+


+

// demand rate ugens in TZeroXBufRd should always use inf as repeats arg

+


+

(

+

~maxTrigRate = s.sampleRate / s.options.blockSize;

+


+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(MouseX.kr(10, ~maxTrigRate)),

+

zeroX: Dseq([2, 3], inf),

+

rate: 0.2

+

) * 0.1

+

}.play

+

)

+


+

s.scope

+


+

x.release

+


+

// In this example waveforms are slightly crossing the x axis.

+

// This comes from the fact that buffer values at zero crossing positions are not equal zero,

+

// but just of a different sign than the sample before.

+

// The effect is also explained in ZeroXBufRd's help Ex.7.

+


+

(

+

{

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(150),

+

zeroX: Dseq([2, 3], inf),

+

rate: 0.2

+

) * 0.2

+

}.plot(0.03)

+

)

+


+


+

// To get cleaner waveforms it's therefore recommended to adjust zero crossings in the buffer.

+

// This can also be done while analysis by using the flag 'adjustZeroXs' in ZeroXBufWr.

+


+

b.adjustZeroXs(z)

+


+


+

// smoother result

+


+

(

+

{

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(150),

+

zeroX: Dseq([2, 3], inf),

+

rate: 0.2

+

) * 0.2

+

}.plot(0.03)

+

)

+


+


+

// mul and dir can be used in the same way as with ZeroXBufRd

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(MouseX.kr(30, ~maxTrigRate)),

+

zeroX: Dseq([2, 3], inf) + LFDNoise0.ar(10).range(0, 5),

+

mul: Dseq([0.05, 0.1, 0.35], inf),

+

rate: 0.5,

+

dir: Dseq([1, -1], inf),

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// unlike with ZeroXBufRd with rate there's no restriction for using 

+

// combinations of demand rate and normal ugens

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(MouseX.kr(30, ~maxTrigRate)),

+

zeroX: Dseq([2, 3], inf),

+

mul: Dseq([0.05, 0.1, 0.35], inf),

+

rate: Dseq([0.2, 0.5, 1], inf) * SinOsc.ar(5).range(0.8, 1.2),

+

dir: Dseq([1, -1], inf),

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// power arg

+

// be careful with this arg moving away from 1 ! 

+

// high power values can result in loud signals if the source has values outside [-1, 1] and

+

// small power values can also become loud with source values near zero

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(MouseX.kr(30, ~maxTrigRate)),

+

zeroX: Dseq([2, 3], inf),

+

power: MouseY.kr(0.3, 2),

+

rate: 0.2,

+

dir: Dseq([1, 1, 1, -1], inf),

+

).tanh * 0.3

+

}.play

+

)

+


+

x.release

+


+


+

Ex.2) The 'xNum' and 'xRep' args

+


+

// needs Buffers from Ex.1

+


+

// With ZeroXBufRd repetitions of (groups of) half wavesets can easily be defined

+

// with passing appropriate demand rate ugens to the zeroX arg.

+

// With TZeroXBufRd the situation is different as the use of an external trigger

+

// opens the freedom to specify the sequences of such groups independently.

+


+

// The following plots show the options in the case of non-overlapping groups.

+


+


+

// Half waveset and full waveset at indices 2 and 3

+


+

(

+

{

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(100),

+

xNum: Dseq([1, 2], inf),

+

zeroX: Dseq([2, 3], inf),

+

rate: 0.2

+

);

+

}.plot(0.03)

+

)

+


+

// Repeated half wavesets

+


+

(

+

{

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(50),

+

xRep: 3,

+

zeroX: Dseq([2, 3], inf),

+

rate: 0.2

+

);

+

}.plot(0.05)

+

)

+


+


+

// Sequencing half waveset number and repetitions

+


+

(

+

{

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(50),

+

xNum: Dseq([1, 2, 3], inf),

+

xRep: Dseq([3, 2, 1], inf),

+

zeroX: Dseq([2, 3], inf),

+

rate: 0.2

+

);

+

}.plot(0.14)

+

)

+


+


+


+


+

Ex.3) The 'overlapSize' arg

+


+


+

// TZeroXBufRd enables overlappings of half wavesets, the maximum number of

+

// overlaps is given with the non-modulatable arg 'overlapSize' which defaults to 10.

+

// So if waveset groups are too long and/or the trigger rate is too high

+

// groups will be cut and the synthesis, according to the other passed args, fails.

+


+

// Supposed constant values, the minimum necessary overlapSize can be calculated

+

// by the formula:

+


+

// ceiling((wavesetGroupSampleNum * trigRate) / (sampleRate * rate))

+


+

// where wavesetGroupSampleNum means the number of samples of a group,

+

// which consists of xNum * xRep half wavesets.

+


+


+

// It's the user's responsibility to care for a sufficiently large overlapSize,

+

// resp. sufficiently low trigger rates, xNum and xRep args as well as not too low playback rates.

+

// With recorded sounds it might be necessary to estimate the largest half wavesets

+

// by analysis in the language.

+


+

// An easy way to reduce the maximum and average half waveset length is 

+

// repeating the zeroX analysis with a LeakDC or high pass filter applied.

+


+


+

// Buffers from Ex.1

+

// We suppose a sample rate of 44100

+


+

b.loadToFloatArray(action: { |b| v = b })

+


+

z.loadToFloatArray(action: { |b| w = b })

+


+

// zero crossing analysis data

+


+

w

+


+

// with zeroX = 1 and xNum = 7 we have a chunk of 194 samples

+


+

w[8] - w[1]

+


+


+

// according to the above formula, with a trigger rate of 500 and

+

// a playback rate of 0.5 the minimal necessary overlapSize is 5

+


+

194 * 500 / (44100 * 0.5)

+


+

-> 4.3990929705215

+


+

// check with overlapSizes of 5 (or higher),

+

// it's the same and sounding smooth,

+

// with overlapSize = 4 the result is erroneous, resp. distorted

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(500),

+

zeroX: 1,

+

xNum: 7,

+

rate: 0.5,

+

overlapSize: 5,

+

) * 0.1

+

}.play

+

)

+


+

s.scope

+


+

x.release

+


+


+


+

Ex.4) Multichannel usage and the 'bufMix' arg

+


+

// This is very simliar to the conventions of ZeroXBufRd,

+

// buffers can be switched per trigger.

+


+

// Without passing a bufMix arg the size of the returned signal is determined by the buffer input. 

+

// It may be a single channel buffer or an array of single channel buffers, 

+

// in correspondence with the analysis buffer(s) - multichannel buffers are not allowed. 

+

// If bufMix is passed, it determines the size of the returned signal, 

+

// its components can be demand rate or other ugens to control switching between buffers per half waveset groups.

+


+

// Note: buffer switching can become CPU-demanding with a lot of Buffers 

+

// as for fast switching it is necessary to play all in parallel

+


+

(

+

// boot with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.options.memSize = 8192 * 32; 

+

s.reboot;

+

)

+


+


+

// prepare 3 buffers

+


+

(

+

b = { Buffer.alloc(s, 1000, 1) } ! 3;

+

z = { Buffer.alloc(s, 100, 1) } ! 3;

+

)

+


+

// fill with basic waveforms

+

(

+

{

+

var src = [

+

SinOsc.ar(400),

+

LFTri.ar(400),

+

SinOsc.ar(400) ** 10

+

];

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+


+

s.scope

+


+

// play 2 channels with sine and triangle, where

+

// triangle is alternating between half and full waveset

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(100),

+

xNum: [2, Dseq([1, 2], inf)],

+

zeroX: 0,

+

bufMix: [0, 1]

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

// sequencing repetitions

+

// if both channels should get the same sequence wrap demand rate ugen into a Function

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(100),

+

xNum: 1,

+

xRep: { Dseq((1..5), inf) },

+

zeroX: 0,

+

bufMix: [0, 1],

+

rate: 0.7

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

// overlapping groups

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(100),

+

xNum: 1,

+

xRep: [Dseq((1..15), inf), Dseq((15..1), inf)],

+

zeroX: 0,

+

bufMix: [0, 1],

+

rate: MouseX.kr(0.2, 3),

+

overlapSize: 10

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

// estimate the maximum xRep for the given overlapSize,

+

// in the above example (suppose samplerate 44100):

+

// as the buffers have been generated with freq = 400,

+

// we can roughly estimate the half wavesets with 55 samples.

+


+

// According to the formula of Ex. 2

+


+

55 * xRep * 100 / (44100 * 0.2) = 10

+


+

xRep = (44100 * 0.2) * 10 / (55 * 100)

+


+

-> 16.036363636364

+


+

// so with xRep values up to 17 we get a bit of distortion besides the aliasing (hardly audible),

+

// it gets stronger with lower overlapSize and disappears with higher values

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(100),

+

xNum: 1,

+

xRep: [Dseq((1..17), inf), Dseq((17..1), inf)],

+

zeroX: 1,

+

bufMix: [0, 1],

+

rate: 0.2,

+

overlapSize: 10   // check with higher and lower values

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+


+

// alternating buffers in one channel

+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(100),

+

xNum: 2,

+

xRep: 1,

+

zeroX: 1,

+

bufMix: Dseq([0, 1], inf),

+

rate: 0.6,

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

// various sequences in both channels with switched waveforms

+


+

(

+

x = {

+

TZeroXBufRd.ar(

+

b, z,

+

trig: Impulse.ar(200),

+

xNum: [Dseq([1, 2], inf), Dseq([2, 1], inf)],

+

xRep: [Dseq([1, 2], inf), Dseq([2, 1], inf)],

+

zeroX: 0,

+

bufMix: [Dseq([0, 1, 2], inf), Dseq([1, 2, 0], inf)],

+

rate: MouseX.kr(0.2, 2),

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+

Ex.5) The overall envelope

+


+

// This works also like for ZeroXBufRd, 'length' refers to the maximum number of triggers for half waveset groups.

+

 

+

// The finishing of a TZeroXBufRd is not detemined by finite demand rate ugens but by an overall envelope, 

+

// its release section is triggered by a maximum number of half wavesets ('length') or a maximum time. 

+


+

// Buffers from Ex.4

+


+

{ TZeroXBufRd.ar(b[0], z[0], trig: Impulse.ar(500), rate: 1, length: 10, rel: 0.01) }.plot(0.05)

+


+

{ TZeroXBufRd.ar(b[0], z[0], trig: Impulse.ar(500),  rate: 1, maxTime: 0.02, rel: 0.01) }.plot(0.05)

+


+


+

// envelopes can be differentiated

+


+

{ TZeroXBufRd.ar(b[0..1], z[0..1], trig: Impulse.ar(500), rate: 1, maxTime: [0.01, 0.005], rel: [0.005, 0.02]) }.plot(0.03)

+


+

{ TZeroXBufRd.ar(b[0..1], z[0..1], trig: Impulse.ar(500), rate: 1, length: [7, 2], rel: [0.005, 0.02]) }.plot(0.03)

+


+


+

// there should be only one doneAction 2 in this case

+


+

{ TZeroXBufRd.ar(b[0..1], z[0..1], trig: Impulse.ar(500), rate: 1, maxTime: [0.01, 0.005], rel: [0.05, 0.5], doneAction: [0, 2]) }.play

+


+


+

(

+

b.do(_.free);

+

z.do(_.free);

+

)

+


+


+

Ex.6) Simultaneous writing and reading

+


+


+

// The reading of half wavesets can start before analysis is finished,

+

// if TZeroXBufRd is carefully used in with a bit of delay.

+

// A bit more delicate than with ZeroXBufRd because of the independent trigger.

+


+


+

// prepare buffers

+


+

(

+

p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";

+

b = Buffer.read(s, p);

+

)

+


+

(

+

z = Buffer.alloc(s, b.duration * 44100 / 5, 1);

+

s.scope;

+

)

+


+

// Simultaneous writing and reading is easier with ZeroXBufRd 

+

// as the trigger deltas are given by the source then.

+


+

(

+

{

+

var src = PlayBuf.ar(1, b, BufRateScale.ir(b));

+

// write zero crossings, but no need to overwrite sound buffer

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, writeSndBuf: 0);

+

DelayL.ar(

+

TZeroXBufRd.ar(

+

b, z,

+

// indicating stereo

+

bufMix: [0, 0],

+

// one trigger for both channels

+

// sufficiently slow progress for the given source

+

// (can not be guaranteed for an arbitrary signal)

+

trig: TDuty.ar(Dstutter(5, Dseq([1, 5, 10], inf)) * ControlDur.ir),

+

xNum: 1,

+

xRep: 2,

+

// stereo, drate ugens must be wrapped

+

zeroX: { Dseries() },

+

rate: { Dwhite(0.5, 0.7) }, 

+

maxTime: 7,

+

rel: 1,

+

doneAction: 2

+

),

+

0.1,

+

0.1

+

);

+

}.play

+

)

+


+

(

+

b.free;

+

z.free;

+

)

+


+

// It's of course unproblematic – and still quasi realtime – to fully a analyse 

+

// a snippet of sound with ZeroXBufWr before freely using TZeroXBufRd in the same synth

+


+


+

Ex.7) Granulation with movement through a buffer

+


+

// See Buffer Granulation tutorial, Ex. 1h

+


+ + diff --git a/Help/VarGui shortcut builds.html b/Help/VarGui shortcut builds.html new file mode 100644 index 0000000..d302c78 --- /dev/null +++ b/Help/VarGui shortcut builds.html @@ -0,0 +1,1099 @@ + + + + + + + + + + + +

VarGui shortcut builds quick building of slider / player guis for synths and sequencing

+


+

Part of: miSCellaneous

+


+

See also: VarGui, HS with VarGui, PLx suite, Buffer Granulation

+


+


+

VarGui allows combined control of Synths, Pbinds / EventStreamPlayers and Tasks in one GUI. Many of its options though may not be relevant for most usages, also control specs were to be given directly (changed with v0.5). Shortcut build methods take advantage of SynthDef controlspec metadata, if defined (or global ControlSpecs), and autogenerate Pbinds for sequencing. Controls and Pbinds can be customized with options. 

+

Main tools are the methods sVarGui (synth), pVarGui (pattern) and compound builders spVarGui / psVarGui. Methods sVarGui / pVarGui, applied to a single Symbol / String, produce a VarGui for one or more Synth(s) or Pbind(s) based on the referred single SynthDef (Exs. 1a, 1b, 2a, 2b). Both methods also apply to collections of SynthDef names (3a, 3b), whereas spVarGui and psVarGui, builders of mixed Synth / Pbind VarGuis, expect collections of two items which may be Symbols / Strings or collections of Symbols / Strings (3c).

+

Examples are using Patterns from dynamic scope PLx suite for conveniently refering to environmental variables.

+


+


+

1.) Synth GUIs

+


+

Example 1a:   default instrument 

+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// No metadata is defined with default instrument, per default global ControlSpecs are used.

+

// Here its definition from Event.sc:

+


+

(

+

SynthDef(\default, { arg out=0, freq=440, amp=0.1, pan=0, gate=1;

+

var z;

+

z = LPF.ar(

+

Mix.new(VarSaw.ar(freq + [0, Rand(-0.4,0.0), Rand(0.0,0.4)], 0, 0.3)),

+

XLine.kr(Rand(4000,5000), Rand(2500,3200), 1)

+

) * Linen.kr(gate, 0.01, 0.7, 0.3, 2);

+

OffsetOut.ar(out, Pan2.ar(z, pan, amp));

+

}, [\ir]).storeOnce;

+

)

+


+


+

// With the next line you should get a VarGui with controls for freq, amp, pan and gate.

+

// In SC 3.5.0 gate isn't stored anymore in global ControlSpecs, so it won't be there.

+

// If you encounter other differences, global ControlSpecs and / or the 

+

// default instrument have probably been changed,

+

// see below how to display and change global Specs.

+

// In global ControlSpecs amp (and, if there, gate) default to 0, 

+

// you have to raise both in order to hear sound after pressing the player button.

+


+

\default.sVarGui.gui;

+


+


+

// automatic use of global ControlSpecs turned off, Synths with default args

+


+

\default.sVarGui(useGlobalSpecs: false).gui;

+


+


+

// global specs, not all of them ControlSpecs, are stored in Spec.specs ...

+


+

Spec.specs.associationsDo(_.postln);

+


+


+

// ... they can be added or replaced with .add

+

// for default instrument examples 

+

// we replace \amp spec with a new ControlSpec with default 0.1 

+


+

Spec.add(\amp, [0, 1, \lin, 0, 0.1]);

+


+


+

// generating a number of Synths, controls can be excluded,

+

// parallel slider dragging with Alt, parallel button action with Shift-click

+


+

\default.sVarGui(exclude: [\gate, \pan],  num: 3).gui;

+


+


+


+

// controls can be replaced ...

+


+

\default.sVarGui(ctrReplace: [\freq, [400, 440, \exp, 0, 420]], exclude: \gate).gui;

+


+


+

// ... and added, before or after the main block of controls from metadata or global ControlSpecs,

+

// this collection is empty here, so ctrBefore and ctrAfter are equivalent

+


+

\default.sVarGui(useGlobalSpecs: false, ctrBefore: [\freq, [400, 440, \exp, 0, 420]]).gui;

+


+


+

// bad definition, \freq is already used as global ControlSpec 

+


+

\default.sVarGui(ctrBefore: [\freq, [300, 1000, \exp, 0, 440]]).gui; // WRONG

+


+


+


+

Example 1b:   SynthDefs including metadata 

+


+


+

SynthDef with defined controlspec metadata. The specs can be stored as ControlSpecs or Arrays, may also be Symbols / Strings refering to the global dictionary of Specs (Spec.specs). It's only convention to store specs under the key \specs, it can be anything else, and nothing prevents you from storing more than one dictionary of ControlSpecs per SynthDef - the VarGui shortcut methods have a metaKey arg (default: \specs) which determines where to lookup in the metadata dictionary.

+


+


+

(

+

SynthDef(\buzz, { arg freq = 400, out, gate = 1, freqDev = 0.01, att = 0.01, dec = 0.01, susLevel = 0.5, rel = 1, 

+

cutoff = #[1000, 1000, 1000], rq = 0.25, amp = 0.2, preAmp = 1, maxDelay = 0.03;

+

    var src, srcFreq, sig;

+

    sig = Mix.fill(3, { |i|

+

    // chorus spread over three registers 

+

    srcFreq = (2 ** i) * freq * (1 + Rand(freqDev.neg, freqDev)) / 2;

+

    src = RLPF.ar(Saw.ar(srcFreq, preAmp), cutoff[i], rq).softclip * amp * 

+

    EnvGen.kr(Env.adsr(att, dec, susLevel, rel), gate, doneAction: 2);

+

    // random spatialization (for sequencing) by L/R delay

+

    [DelayL.ar(src, maxDelay, Rand(0, maxDelay)), DelayL.ar(src, maxDelay, Rand(0, maxDelay))]

+

}) ;

+

    // ensure sample accurate output for events of short durations    

+

    OffsetOut.ar(out, sig);

+

    

+

    }, metadata: (

+

    specs: (

+

    freq: [20, 5000, \exp, 0, 80],

+

    gate: [0, 1.0, \lin, 0, 1],

+

     freqDev: [0.0, 0.02, \lin, 0, 0.002],

+

  att: [0.01, 0.2, \lin, 0, 0.01],

+

    dec: [0.01, 0.2, \lin, 0, 0.01],

+

    susLevel: [0.01, 1, \lin, 0, 0.5],

+

    rel: [0.01, 2, \exp, 0, 1],

+

    cutoff: [200, 5000, \exp, 0, 1000],

+

    rq: [0.1, 0.9,\lin, 0, 0.2],

+

    amp: [0.0, 1, \lin, 0, 0.2],

+

    preAmp: [0.9, 5, \lin, 0, 1],

+

    maxDelay: [0, 0.01, \lin, 0, 0.002]

+

    ),

+

    // doesn't matter for VarGui if spec defined as Array or ControlSpec,

+

    // an arbitrary number of arbitrarily named alternative Spec Events may be passed,

+

    // for non-sequencing use adsr params may be dropped

+

    basicSpecs: (

+

    freq: [20, 5000, \exp, 0, 80],

+

    gate: [0, 1.0, \lin, 0, 1],

+

    cutoff: [200, 5000, \exp, 0, 1000],

+

    rq: [0.1, 0.9,\lin, 0, 0.2],

+

    amp: [0.0, 1, \lin, 0, 0.2],

+

    preAmp: [0.9, 5, \lin, 0, 1]

+

    )

+

    ) 

+

).add;

+

)

+


+


+

// here metadata includes a gate spec with default 1

+

// metadata has priority over global ControlSpecs

+

// metaKey \specs used per default

+


+

\buzz.sVarGui.gui;

+


+


+

// use gui options for better arrangement 

+


+

\buzz.sVarGui(num: 4).gui(tryColumnNum: 2, sliderHeight: 16);

+


+


+

// alternative metadata, metaKey to be passed,

+

// mostly sounds different from last version 

+

// because of fixed max chorus-width param freqDev

+


+

\buzz.sVarGui(num: 4, metaKey: \basicSpecs).gui(tryColumnNum: 2);

+


+


+


+

2.) Sequencing GUIs

+


+


+

Controlling Pbinds / EventStreamPlayers with VarGui is based on (a) the setting of environmental variables and (b) the proper definition of Pbinds with Patterns of PLx suite or Patterns with functional code (Event patterns and Functions) so that EventStreamPlayers get the updated variable values in the following events.

+


+


+

Basic example of a Pbind to get envir values:

+


+


+

p = Pbind(

+

\dur, Pfunc { ~dur } * Pseq([2,1,1], inf), 

+

\legato, Pfunc { ~legato }, 

+

\amp, Pfunc { ~amp } 

+

)

+


+

// or

+


+

p = Pbind(

+

\dur, PL(\dur) * Pseq([2,1,1], inf), 

+

\legato, PL(\legato), 

+

\amp, PL(\amp) 

+

)

+


+

Especially when based on a SynthDef with a large number of args writing a Pbind can be lengthy, moreover redundant if there are many pbind pairs of the form 

+


+


+

[ aSymbol, Pfunc { ~aSymbol } ] 

+


+


+

The pVarGui method is going the opposite way: Pbind pairs get this most simple form for all args with metadata or global ControlSpecs defined, though it's possible to exclude keys and add respectively replace customized pairs before and after the automatically generated ones. All you need is a SynthDef that is suited for Pbind sequencing (known to SynthDescLib by being added, properly defined Envelopes).

+

WARNING: as a lot of the underlying Pbind structure (by default all of it !) is hidden, it's possible to call pVarGui without knowing anything about Patterns. Nevertheless it's highly recommended to be aware of the mechanisms of Pbind for applying useful sequencing customizations and having a look at the fully written Pbind examples in VarGui. Clearly: adding, replacing and excluding Pbind pairs without seeing the resulting code is a possible source of error, so if using VarGui this way better start slowly and go on stepwise. With the post option you can print out the ordered list of pairs.

+


+


+

Example 2a:   default instrument 

+


+


+

// for default instrument examples 

+

// we replace \amp spec with a new ControlSpec with default 0.1 

+


+

Spec.add(\amp, [0, 1, \lin, 0, 0.1]);

+


+


+

// Most simple example to get a VarGui controlling a Pbind / EventStreamPlayer with 

+

// default instrument, control of duration and legato is automatically added.

+

// As with the sVarGui method synth controls are added when found in metadata definition 

+

// or global ControlSpecs, different from sVarGui \gate is excluded by default.

+


+

\default.pVarGui.gui;

+


+


+

// adding a pattern pair - if it contains one of the keys \note, \midinote or \degree

+

// the freq pair is removed automatically, see posted Pbind pairs 

+


+

\default.pVarGui(pAfter: [\degree, Pwhite(0,5)], post: true).gui;

+


+


+

// pattern pair replacement as in basic example above

+


+

\default.pVarGui(pReplace: [\dur, PL(\dur) * Prand([2,1,1], inf)] ).gui;

+


+


+

// adding a pattern pair after the main block of pairs,

+

// same effect as before

+


+

\default.pVarGui(pAfter: [\dur, Pkey(\dur) * Prand([2,1,1], inf)], post: true).gui;

+


+


+

// Internally a Pbind of this form had been generated (see post window), 

+

// in each Event the second Stream with key \dur gets the value from the first, 

+

// overrides it in the Event. 

+


+

Pbind(

+

// pBefore pairs (optinally passed to pVarGui) 

+

...

+

+

// these are always placed before the main block

+

\instrument, \default,

+

\dur, Pfunc { ~dur },

+

\legato, Pfunc { ~legato },

+

+

// main block of pairs corresponding to args for which 

+

// spec definition was found (if not excluded or replaced), 

+

// ordered like in SynthDef

+

+

\freq, Pfunc { ~freq },

+

\amp, Pfunc { ~amp },

+

\pan, Pfunc { ~pan },

+

+

// pAfter pairs (optinally passed to pVarGui)

+

\dur, Pkey(\dur) * Prand([2,1,1], inf)

+

)

+


+

+

// Additional arrayed control for simple step sequencing with random init values. 

+

// The PLseq degree pattern defaults to repeats = inf and envir = \current.

+

// It would take values from the current Environment of streamification.

+


+

// Here playing and setting the variables will 

+

// happen in a new Environment generated by the VarGui.

+


+

(

+

\default.pVarGui(

+

ctrBefore: [\a, { [0, 5, \lin, 1, rrand(0,6)] } ! 8 ],

+

pBefore: [\degree, PLseq(\a) ]

+

).gui;

+

)

+


+

// A number of Pbinds and control sets can be generated with the num arg,

+

// control and pattern customization args take Functions (optionally of indices)

+

// for expansion.

+


+

// This a potentially powerful feature, also suited for producing a real mess !

+

// Especially think of possibly inappropriate ranges ! 

+

// If you are unsure try out evaluating code of the form ...

+


+

{ |i| ... } ! n

+


+

// ... separately before plugging in the shortcut methods.

+


+


+

// Here the Function passed to ctrBefore has no index arg, 

+

// it just produces 4 different tuples of 

+

// init values for the step sequencers,

+


+

// the pBefore Function determines 4 different octave registers

+

// quant arg ensures staying in sync based on the passed rhythmic patterns

+


+

(

+

\default.pVarGui(

+

/* ctrBefore: */ { [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ] },

+

/* ctrReplace: */ [\dur, [0.2, 0.6, \lin, 0.2, 0.2]],

+

pBefore: { |i| [\degree, PLseq(\a), \octave, i+4] },

+

num: 4,

+

quant: 0.2,

+

post: true 

+

).gui(tryColumnNum: 2);

+

)

+


+


+


+

Example 2b:   SynthDefs including metadata 

+


+


+

Automatic Pbind generation in VarGui shortcut builds is especially saving typing if SynthDefs have a lot of args and controlspec metadata defined.

+


+

// most simple, controls are built for all args with metadata defined

+

// arrayed args are detected and controls are established for a corresponding array

+

// SynthDef from above

+


+

\buzz.pVarGui.gui;

+


+


+

// use the exclude option to exclude from automatically generated controls and Pbind pairs

+

// you would want to do that for a static value or sequencing not to be gui-controlled

+

 

+

 

+

// always SynthDef default value 0.01 for attack time 

+


+

\buzz.pVarGui(exclude: [\att], post: true).gui;

+


+


+

// sequencing without control

+

// RLP filter rq excluded from gui control and automatic Pbind pair generation, 

+

// though added to Pbind pairs again as passed to pBefore (could also be pAfter),

+

// here PLseq taken as it defaults to inf

+


+

\buzz.pVarGui(exclude: [\rq], pBefore: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui;

+


+


+

// same effect on sound, but we have a useless rq control

+


+

\buzz.pVarGui(pAfter: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui;

+

\buzz.pVarGui(pReplace: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui;

+


+


+

// here the pBefore arg is useless as the Pfunc that takes controlled values 

+

// comes after in execution and will overwrite the value per Event

+


+

\buzz.pVarGui(pBefore: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui;

+


+


+

// establishing a cutoff freq rhythm for all three layers

+

// remember that in Pbinds arrayed args must be distinguished from the syntax for generating 

+

// multiple synths per Event, this can be achieved by wrapping in an additional array

+


+

\buzz.pVarGui(pReplace: [\cutoff, Pfunc { [~cutoff] } * PLseq([3,1,1]) ]).gui; 

+


+


+


+

// step sequencer for quartertone bassline

+


+

(

+

\buzz.pVarGui(

+

ctrAfter: [\a, { var lo = 25, hi = 50; [lo, hi, \lin, 0.5, rrand(lo*2, hi*2) / 2 ] } ! 8 ],

+

pBefore: [\midinote, PLseq(\a)],

+

post: true

+

).gui;

+

)

+


+


+


+

// step sequencer with two voices

+

// by passing functions different control ranges and registers are established

+

// both lines are in a quartertone scale but shifted by an eigthtone

+

// lines itself can be shifted by an offset ~add

+


+

// modifier keys can be used to perform parallel slider or button actions

+

// alt for parallel slider movement and shift for parallel button actions (VarGui)

+

 

+


+

(

+

\buzz.pVarGui(

+

ctrReplace: [\dur, [0.1, 0.2, \lin, 0.1, 0.2], \amp, [0.0, 0.5, \lin, 0, 0.3]],

+

ctrAfter: { |i| var d = 0.25; 

+

[\add, [-12, 12, \lin, 0.5, 0],

+

\a, { [(i*d), 11.5 + (i*d), \lin, 0.25, rrand(0, 23) / 2 + (i*d)] } ! 8

+

] },

+

pBefore: { |i| [

+

\note, PLseq(\a) + PL(\add), 

+

\octave, 3 + (i*4) + Pwhite(0,1) 

+

] },

+

quant: 0.2,

+

post: true,

+

num: 2

+

).gui(tryColumnNum: 2);

+

)

+


+


+

Example 2c:   Combination of parameter control and pattern exchange (JITLib)

+


+


+

(

+

\buzz.pVarGui(

+

ctrReplace: [\freq, [20, 1000, \exp, 0, 80]],

+

pReplace: [

+

\cutoff, Pdefn(\co, Pseq([3, 1, 1, 1, 1], inf)) * Pfunc { [~cutoff] },

+

\freq, Pdefn(\fr, Pseq([1, 1, 1.3, 1.2, 1], inf)) * Pfunc { ~freq }

+

]

+

).gui;

+

)

+


+

// start from gui and eval pattern replacements before playing around with sliders

+


+

Pdefn(\fr, Pseq([1, 1, 1.7, 1.3, 1.2], inf));

+


+

Pdefn(\co, Pseq([2, 1, 1], inf));

+


+

Pdefn(\fr, 1);

+


+

Pdefn(\co, Pseq([1, 2, 1.7, 1.3, 1.2], inf));

+


+


+


+

Example 2d:   Combination of parameter control and pattern exchange (PLx)

+


+


+

// above done with PL

+

// note that PLs are taking envir variables from the current Environment by default,

+

// this is ok for the variables set by VarGui (freq) in its Environment,

+

// but for PLs to take values from elsewhere we must give the Environment explicitely.

+

// Suppose we are in topEnvironment here:

+


+

// As PL defaults to repeats = inf, Pseq can be taken without a repeats arg 

+

// for endless looping

+


+

(

+

~co = Pseq([3, 1, 1, 1, 1]);

+

~fr = Pseq([1, 1, 1.3, 1.2, 1]);

+


+

\buzz.pVarGui(

+

ctrReplace: [\freq, [20, 1000, \exp, 0, 80]],

+

pReplace: [

+

\cutoff, PL(\co, envir: \top) * Pfunc { [~cutoff] },

+

\freq, PL(\fr, envir: \top) * PL(\freq)

+

]

+

).gui;

+

)

+


+

// start from gui and eval pattern replacements before playing around with sliders

+


+

~fr = Pseq([1, 1, 1.7, 1.3, 1.2]);

+


+

~co = Pseq([2, 1, 1]);

+


+

~fr = 1;

+


+

~co = Pseq([1, 2, 1.7, 1.3, 1.2]);

+


+


+

//////////////////////////////////

+


+


+

// alternative version with a PLseq placeholder

+


+

(

+

~co = [3, 1, 1, 1, 1];

+

~fr = [1, 1, 1.3, 1.2, 1];

+


+

\buzz.pVarGui(

+

ctrReplace: [\freq, [20, 1000, \exp, 0, 80]],

+

pReplace: [

+

\cutoff, PLseq(\co, envir: \top) * Pfunc { [~cutoff] },

+

\freq, PLseq(\fr, envir: \top) * PL(\freq)

+

]

+

).gui;

+

)

+


+

// start from gui and eval pattern replacements before playing around with sliders

+


+

~fr = [1, 1, 1.7, 1.3, 1.2];

+


+

~co = [2, 1, 1];

+


+

~fr = [1];

+


+

~co = [1, 2, 1.7, 1.3, 1.2];

+


+


+


+


+

3.) Mixed GUIs

+


+


+

To control Synths or Pbinds / EventStreamPlayers derived from more than one SynthDef sVarGui and pVarGui can be applied to collections.

+


+


+

Example 3a:   Synths from different SynthDefs

+


+


+

// for default instrument examples 

+

// we replace \amp spec with a new ControlSpec with default 0.1 

+


+

Spec.add(\amp, [0, 1, \lin, 0, 0.1]);

+


+


+

// different synths 

+


+

[\buzz, \default].sVarGui.gui

+


+


+

// in basic form this works equivalently ...

+


+

VarGui(synth: [\buzz, \default]).gui;

+


+


+

// ... but for customization the shortcut method sVarGui is more convenient,

+

// otherwise you'd have to pass or generate controls explicitely (5b).

+

// sVarGui and pVarGui, applied to SequenceableCollections, expect Dictionaries

+

// of pairs argName / arg, so you can pass Events.

+

// Their number must equal the collection's size.

+


+

(

+

[\buzz, \default].sVarGui(

+

(ctrReplace: [\freq, [97, 103, \exp, 0, 99]]),

+

(ctrReplace: [\freq, [194, 206, \exp, 0, 201]], exclude: \gate)

+

).gui;

+

)

+


+

// more synths

+


+

(

+

[\default, \buzz].sVarGui(

+

(ctrReplace: { [\freq, [194, 206, \exp, 0, rrand(194.0, 206)]] }, exclude: \gate, num: 4),

+

(ctrReplace: [\freq, [97, 103, \exp, 0, 99]])

+

).gui(tryColumnNum: 2, allowSynthBreak: false);

+

)

+


+


+


+

Example 3b:   Pbinds from different SynthDefs

+


+


+

// overtones, deviations of pitch and pulsation 

+


+

(

+

[\default, \buzz].pVarGui(

+

(ctrReplace: { |i| var f = (2*i + 1) * 100, d = 0.2, lo = 0.99, hi = 1.01; 

+

[\freq, [f*lo, f*hi, 0, 0, f*rrand(lo,hi)], \dur, [d*lo, d*hi, 0, 0, d*rrand(lo,hi)] ] }, 

+

exclude: \gate, 

+

post: true,

+

num: 4),

+

(ctrReplace: [\freq, [97, 103, \exp, 0, 99], \dur, [0.195, 0.205, 0, 0, 0.2] ])

+

).gui(tryColumnNum: 2, allowEnvirBreak: false)

+

)

+


+


+

// step sequencer 

+


+

(

+

[\buzz, \default].pVarGui((

+

ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ],

+

ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]],

+

pBefore: [\degree, PLseq(\a), \octave, 3], 

+

quant: 0.2

+

),(

+

ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ],

+

ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]],

+

pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), 

+

\octave, Pwhite(5,7) ], 

+

quant: 0.2

+

)

+

).gui(tryColumnNum: 2, allowEnvirBreak: false);

+

)

+


+


+


+

Example 3c:   Synths and Pbinds 

+


+


+

// Pbind granulation with \buzz, controls and pbind pairs adapted and added, 

+

// psVarGui (pbind input first) and spVarGui (synth input first)

+

// apply to collections of two items.

+


+

// If only one type of SynthDef is to be used for Pbind(s) or Synth(s)

+

// it may be a plain Symbol / String, the corresponding arg tuples may

+

// be given as plain (not collected) Dictionaries

+


+

// Keep in mind that nevertheless one Dictionary may produce 

+

// more than one Synth (Pbind)

+


+

(

+

[\buzz, \default].psVarGui(

+

(

+

ctrReplace: [\dur, r = [0.01, 0.05, \lin, 0, 0.03], 

+

\rel, r,

+

\freq, [100, 1000, \lin, 0, 100],

+

\amp, [0, 0.5, \lin, 0, 0.15],

+

\legato, [0.1, 2, \lin, 0, 0.5],

+

\freqDev, [0, 0.2, \lin, 0, 0.01]],

+

ctrBefore: [\durDev, [0, 1, \lin, 0, 0.01]],

+

pAfter: [\dur, Pkey(\dur) * Pfunc { x = 1 + ~durDev; rrand(1/x,x) }],

+

post: true

+

),(

+

ctrReplace: { [\dur, [0.01, 0.05, \lin, 0, 0.03],

+

\freq, [100, 1000, \lin, 0, rrand(100, 1000)]] }, 

+

exclude: \gate, 

+

num: 4

+

)

+

).gui(tryColumnNum: 2, allowEnvirBreak: false);

+

)

+


+


+

// If more than one type of SynthDef is to be used for Pbind(s) or Synth(s)

+

// Symbols / Strings must be collected, also the corresponding Dictionaries

+


+

// spVarGui just takes input in reversed order (synth first).

+

// This is independant from representation in the GUI

+

// which can be determined by args sliderPriority (\var or \synth)

+

// and playerPriority (\stream or \synth)

+


+

(

+

[\default, [\buzz, \default]].spVarGui(

+

(

+

ctrReplace: { [\dur, [0.01, 0.05, \lin, 0, 0.03],

+

\freq, [100, 1000, \lin, 0, rrand(100, 1000)]] }, 

+

exclude: \gate, 

+

num: 4

+

),[

+

(

+

ctrReplace: [\dur, r = [0.01, 0.05, \lin, 0, 0.03], 

+

\rel, r,

+

\freq, [100, 1000, \lin, 0, 100],

+

\amp, [0, 0.5, \lin, 0, 0.15],

+

\legato, [0.1, 2, \lin, 0, 0.5],

+

\freqDev, [0, 0.2, \lin, 0, 0.01]],

+

ctrBefore: [\durDev, [0, 1, \lin, 0, 0.01]],

+

pAfter: [\dur, Pkey(\dur) * Pfunc { var x = 1 + ~durDev; rrand(1/x,x) }],

+

post: true

+

),(

+

ctrReplace: [\dur, r = [0.01, 0.05, \lin, 0, 0.03], 

+

\freq, [100, 1000, \lin, 0, 100],

+

\amp, [0, 0.5, \lin, 0, 0.15],

+

\legato, [0.1, 2, \lin, 0, 0.5]],

+

ctrBefore: [\durDev, [0, 1, \lin, 0, 0.01],

+

\freqDev, [0, 0.2, \lin, 0, 0.01]],

+

pAfter: [\dur, Pkey(\dur) * Pfunc { var x = 1 + ~durDev; rrand(1/x,x) },

+

\freq, Pkey(\freq) * Pfunc { var x = 1 + ~freqDev; rrand(1/x,x) }],

+

post: true

+

)

+

]

+

).gui(tryColumnNum: 2, allowEnvirBreak: false, sliderPriority: \synth, playerPriority: \synth);

+

)

+


+


+


+

4.) Differences between shortcut builds and direct VarGui instantiation

+


+


+

.) Shortcut methods apply to Symbols / Strings or collections thereof for Synth and Pbind generation and control. Symbols / Strings refer to the corresponding SynthDefs, known to SynthDesLib.global. For passing Synths, nodeIDs, EventStreamPlayers, also Task Functions and Tasks, you would have to call VarGui directly.

+


+

.) Shortcuts and also direct instantiation (not before v0.5) are using SynthDef metadata and / or global ControlSpecs. Though customization options for specs (exclude, add, replace) are a main feature of the shortcut methods. As a compromise spec- and pbindmaker methods with these options may be plugged into direct instantiation (5b).

+


+

.) The pVarGui method invokes automatic Pbind generation with customization options for Pbind pairs (exclude, pBefore, pAfter, pReplace), VarGui expects Pbinds to be passed directly. As a compromise a pbindmaker method with these options may be plugged into direct instantiation (5b).

+


+

.) In shortcut methods the num arg causes coordinated expansion, all other args (except server) may optionally be given as Functions of indices. With VarGui input you'd have to pass lengthy nested Arrays or write something like { |i| ... } ! n for every arg explicitely, as sizes of input must match. As a compromise spec- and pbindmaker methods with num arg may be plugged into direct instantiation (5b).

+


+

.) Reordering / interleaving of controls of different Environments / Synths (VarGui helpfile Examples 5a and 5b) is not possible with shortcut methods. However this seems to be a quite special feature, with shortcut methods ordering of Synths / Pbinds is primarily defined by order of args, control customization options allow further modifications of order. Finally choosing sliderPriority (\synth or \var first) is a pure gui method option and applies to both ways of VarGui building.

+

+

+


+

5.) Shortcut method specifictions

+


+


+

Shortcut methods also take Functions, that should return args in a valid form. This can be used for defining controls in different ranges in combination with num. See examples above.

+


+


+

5a:   core shortcut methods

+


+

aSynthDefName.sVarGui(ctrBefore, ctrReplace, ctrAfter, exclude, metaKey, useGlobalSpecs, num, server)

+

+

Instantiate a VarGui object for control of one or more Synth(s) derived from a SynthDef name (Symbol / String).

+

Per default controlspecs are taken from metadata definition, if defined with the SynthDef, or

+

the global dictionary Spec.specs. Controls can be excluded with exclude, added with 

+

ctrBefore or ctrAfter and replaced with ctrReplace, this is also the order of operations.

+

+

ctrBefore - a spec pair collection of the form [ key, spec, ...  ] where

+

key is the symbol of the control arg to be set and

+

spec can be a collection of the form [ minval, maxval, warp, step, default ] 

+

defining the corresponding ControlSpec, a Symbol / String to look for a ControlSpec in the

+

global dictionary Spec.specs or a collection of specs of this form

+

for an arrayed control. May also be a SimpleNumber for a dummy slider with fixed value. 

+

Defaults to nil. Also takes a Function of indices that returns a valid arg. 

+

ctrReplace - a spec pair collection of a form like ctrBefore. 

+

Also takes a Function of indices that returns a valid arg. Defaults to nil.

+

ctrAfter - a spec pair collection of a form like ctrBefore. 

+

Also takes a Function of indices that returns a valid arg. Defaults to nil.

+

exclude - a collection of control keys (Symbols) to be excluded. 

+

Also takes a Function of indices that returns a valid arg. Defaults to nil.

+

metaKey - Symbol. Key to lookup SynthDef metadata. 

+

Also takes a Function of indices that returns a Symbol. 

+

Defaults to \specs.

+

useGlobalSpecs - Boolean. Defines if to consider global ControlSpecs if 

+

metadata is not given. Also takes a Function of indices that returns a Boolean. 

+

Defaults to true.

+

num - Integer. Number of Synths to be controlled. Defaults to 1.

+

server - Server. The server to send node messages for synth control. 

+

Defaults to the default server.

+


+

+

aSequenceableCollection.sVarGui(argDictionary1, ... , argDictionaryN, server)

+


+

Instantiate a VarGui object for control of Synths derived from a collection of SynthDef names (Symbols / Strings).

+

Options for Synth controls are taken from the corresponding arg Dictionaries.

+

Size of collection must equal N, the number of Dictionaries. 

+

See aSynthDefName.sVarGui for valid arg syntax.

+

+

server - Server. The server to send node messages for synth control. 

+

Defaults to the default server.

+

+


+

aSynthDefName.pVarGui(ctrBefore, ctrReplace, ctrAfter, durCtr, legatoCtr, pBefore, pReplace, pAfter, exclude, excludeGate, clock, quant, metaKey, useGlobalSpecs, post, trace, num)

+

+

Instantiate a VarGui object for control of one or more Pbind(s) / EventStreamPlayer(s), 

+

derived from a SynthDef name (Symbol / String). One or more Pbind(s) with Pfunc pairs and

+

the corresponding environmental variable controls are generated, 

+

controls for duration and legato are added. 

+

Per default controlspecs are taken from metadata definition, if defined with the SynthDef, or

+

the global dictionary Spec.specs. Controls can be excluded with exclude, added with 

+

ctrBefore or ctrAfter and replaced with ctrReplace; Pbind pairs can be excluded with exclude, 

+

added with pBefore or pAfter and replaced with pReplace, this is the order of operations for 

+

Synths and Pbind pairs. Note that exclude applies to Synth controls and Pbind pairs. 

+

If an added Pbind pair with key \degree, \note or \midinote is detected, \freq is excluded 

+

automatically from Pbind and controls. Gate control is excluded per default.

+

+

ctrBefore - a spec pair collection of the form [ key, spec, ...  ] where

+

key is the symbol of the environmental variable to be set and

+

spec can be a collection of the form [ minval, maxval, warp, step, default ] 

+

defining the corresponding ControlSpec, a Symbol / String to look for a ControlSpec in the

+

global dictionary Spec.specs or a collection of specs of this form

+

for an arrayed control if the environmental variable should have the value 

+

of a collection itself. May also be a SimpleNumber for a dummy slider with fixed value.

+

Defaults to nil. Also takes a Function of indices that returns a valid arg. 

+

ctrReplace - a spec pair collection of a form like ctrBefore. 

+

Also takes a Function of indices that returns a valid arg. Defaults to nil.

+

ctrAfter - a spec pair collection of a form like ctrBefore. 

+

Also takes a Function of indices that returns a valid arg. Defaults to nil.

+

durCtr - a controlspec of the form [ minval, maxval, warp, step, default ]

+

or a Symbol to look for a ControlSpec in the global dictionary Spec.specs. 

+

Also takes a Function of indices that returns a valid arg. 

+

Defaults to #[0.05, 3, \exp, 0, 0.2].

+

legatoCtr - a controlspec of the form [ minval, maxval, warp, step, default ]

+

or a Symbol to look for a ControlSpec in the global dictionary Spec.specs. 

+

Also takes a Function of indices that returns a valid arg. 

+

Defaults to #[0.1, 5, \exp, 0, 0.8].

+

pBefore - a Pbind pair collection of the form [ key, pattern, ...  ]. 

+

Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. 

+

pReplace - a Pbind pair collection of the form [ key, pattern, ...  ]. 

+

Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. 

+

pAfter - a Pbind pair collection of the form [ key, pattern, ...  ]. 

+

Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. 

+

exclude - a control key (Symbol) or a collection of control keys to be excluded from 

+

Pbind pairs and controls. Also takes a Function of indices that returns a valid arg. 

+

Defaults to nil.

+

excludeGate - Boolean. Determines if gate control should be excluded. 

+

Also takes a Function of indices that returns a Boolean. Defaults to true.

+

clock -  TempoClock, nil or collection thereof for playing streams.

+

Also takes a Function of indices that returns a valid arg. 

+

Defaults to the default TempoClock.

+

quant -  Quant, Float, nil or collection thereof used as quant data for playing streams.

+

Also takes a Function of indices that returns a valid arg. 

+

Defaults to Quant.default (none).

+

metaKey - Symbol. Key to lookup SynthDef metadata. 

+

Also takes a Function of indices that returns a Symbol. 

+

Defaults to \specs.

+

useGlobalSpecs - Boolean. Defines if to consider global ControlSpecs if 

+

metadata is not given. Also takes a Function of indices that returns a Boolean. 

+

Defaults to true.

+

post - Boolean. Determines if to post order of Pbind pairs. 

+

Also takes a Function of indices that returns a Boolean. Defaults to false.

+

trace - Boolean. Determines if EventStreamPlayer should post Events when playing. 

+

Also takes a Function of indices that returns a Boolean. Defaults to false.

+

num - Integer. Number of Pbinds / EventStreamPlayers to be controlled. Defaults to 1.

+


+


+

aSequenceableCollection.pVarGui(argDictionary1, ... , argDictionaryN)

+


+

Instantiate a VarGui object for control of Pbinds / EventStreamPlayers derived from a 

+

collection of SynthDef names (Symbols / Strings). Options for controls are taken from the corresponding 

+

arg Dictionaries. Size of collection must equal N, the number of Dictionaries. 

+

See aSynthDefName.pVarGui for valid arg syntax.

+


+


+

The following two methods are equivalent, just take opposite arg order. 

+

This is independant of arrangement, which can be determined by gui args

+

sliderPriority (\var or \synth) and playerPriority (\stream or \synth).

+


+


+

aSequenceableCollection.spVarGui(sVarGuiArgDictionaries, pVarGuiArgDictionaries, server)

+


+

Instantiate a VarGui object for control of Synths and Pbinds / EventStreamPlayers 

+

derived from SynthDef names (Symbols / Strings). Thus receiver must be of the form 

+

[ synthNames, pbindSynthNames ], whereby synthNames and pbindSynthNames

+

may be Symbols / Strings or SequenceableCollections of Symbols / Strings.

+


+

sVarGuiArgDictionaries - arg Dictionary or SequenceableCollection thereof, whose size 

+

must be equal to that of synthNames (if a collection). 

+

See aSynthDefName.sVarGui for valid arg syntax. 

+

Defaults to [].

+

pVarGuiArgDictionaries - arg Dictionary or SequenceableCollection thereof, whose size 

+

must be equal to that of pbindSynthNames (if a collection). 

+

See aSynthDefName.pVarGui for valid arg syntax.

+

Defaults to [].

+

server - Server. The server to send node messages for synth control. 

+

Defaults to the default server.

+


+


+

aSequenceableCollection.psVarGui(pVarGuiArgDictionaries, sVarGuiArgDictionaries, server)

+


+

Instantiate a VarGui object for control of Pbinds / EventStreamPlayers and Synths 

+

derived from SynthDef names (Symbols / Strings). Thus receiver must be of the form 

+

[ pbindSynthNames, synthNames ], whereby pbindSynthNames and synthNames

+

may be Symbols / Strings or SequenceableCollections of Symbols / Strings.

+


+

pVarGuiArgDictionaries - arg Dictionary or SequenceableCollection thereof, whose size 

+

must be equal to that of pbindSynthNames (if a collection). 

+

See aSynthDefName.pVarGui for valid arg syntax.

+

Defaults to [].

+

sVarGuiArgDictionaries - arg Dictionary or SequenceableCollection thereof, whose size 

+

must be equal to that of synthNames (if a collection). 

+

See aSynthDefName.sVarGui for valid arg syntax. 

+

Defaults to [].

+

server - Server. The server to send node messages for synth control. 

+

Defaults to the default server.

+


+


+

5b:   spec- and pbindmaker methods

+


+

In most cases you won't need this, except for reloading customized sequencing VarGuis (6). For special arrangements methods for making specdata and Pbinds of appropriate Pfuncs can be used for customizing control with direct VarGui instantiation. These methods take args in the same way as sVarGui and pVarGui.

+


+


+

// sVarGuiSpecs returns a list of spec pair lists of the form [\key, specArray, ...]

+

// derived from SynthDef metadata / global ControlSpecs,

+

// controls can be excluded, added and replaced

+


+

(

+

VarGui(

+

synth: [\default, \buzz], 

+

synthCtr: \default.sVarGuiSpecs(exclude: \gate) ++

+

\buzz.sVarGuiSpecs(ctrReplace: [\amp, [0, 0.5, 0, 0, 0.1]])

+

).gui;

+

)

+


+

// shorter

+


+

(

+

[\default, \buzz].sVarGui(

+

(exclude: \gate), 

+

(ctrReplace: [\amp, [0, 0.5, 0, 0, 0.1]])

+

).gui;

+

)

+


+


+

// as with sVarGui arguments can be functions of indices 

+


+

(

+

VarGui(

+

synth: \default!4 ++ \buzz, 

+

synthCtr: 

+

\default.sVarGuiSpecs(num: 4, exclude: \gate, 

+

ctrReplace: { |i| var x = i*100 + 400; [\freq, [x, x*1.1, 0, 0, x]] }) ++

+

\buzz.sVarGuiSpecs(ctrReplace: [\amp, [0, 0.5, 0, 0, 0.2]])

+

).gui(tryColumnNum: 2, allowSynthBreak: false);

+

)

+


+

// shorter

+


+

(

+

[\default, \buzz].sVarGui(

+

(num: 4, exclude: \gate, ctrReplace: { |i| var x = i*100 + 400; [\freq, [x, x*1.1, 0, 0, x]] }), 

+

(ctrReplace: [\amp, [0, 0.5, 0, 0, 0.2]])

+

).gui(tryColumnNum: 2, allowSynthBreak: false);

+

)

+


+


+


+

// pVarGuiSpecs also returns a list of spec pair lists, 

+

// just adds specs for dur and legato by default,

+

// pfuncPbinds returns appropriate Pbinds of Pfuncs

+

// additional pairs can be added

+


+

// however, compared to pVarGui, more coordination is the user's responsibility:

+

// specmaker and pbindmaker don't know about each other

+

// useless control \freq excluded explicitely here

+


+

(

+

VarGui(

+

varCtr: 

+

\buzz.pVarGuiSpecs(ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ],

+

ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]], exclude: \freq) ++

+

\default.pVarGuiSpecs(ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ],

+

ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]], exclude: \freq),

+

stream: 

+

\buzz.pfuncPbinds(pBefore: [\degree, PLseq(\a), \octave, 3]) ++ 

+

\default.pfuncPbinds(pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + 

+

PLseq(\a), \octave, Pwhite(5,7)],  post: true),

+

quant: 0.2

+

).gui(tryColumnNum: 2, allowEnvirBreak: false);

+

)

+


+

// shorter

+


+

(

+

[\buzz, \default].pVarGui((

+

ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ],

+

ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]],

+

pBefore: [\degree, PLseq(\a), \octave, 3], 

+

quant: 0.2

+

),(

+

ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ],

+

ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]],

+

pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + 

+

PLseq(\a), \octave, Pwhite(5,7) ], 

+

quant: 0.2

+

)

+

).gui(tryColumnNum: 2, allowEnvirBreak: false);

+

)

+


+


+

aSynthDefName.sVarGuiSpecs(ctrBefore, ctrReplace, ctrAfter, exclude, metaKey, useGlobalSpecs, num)

+

+

Generate control data for one or more Synth(s) derived from a SynthDef name (Symbol / String).

+

Returns a grouped collection, also for num = 1. 

+

Data can directly been used as input to VarGui's synthCtr arg. 

+

This method can be used for control of Synths derived from more than one SynthDef in one VarGui

+

or combined control of Synths and Pbinds / EventStreamPlayers.

+

+

args - see aSynthDefName.sVarGui

+


+


+

aSynthDefName.pVarGuiSpecs(ctrBefore, ctrReplace, ctrAfter, durCtr, legatoCtr, exclude, excludeGate, metaKey, useGlobalSpecs, num)

+

+

Generate envir variable control data for one or more Environments derived from 

+

a SynthDef name (Symbol / String). Returns a grouped collection, also for num = 1. 

+

Data can directly been used as input to VarGui's varCtr arg. 

+

This method can be used for control of Pbinds / EventStreamPlayers derived from 

+

more than one SynthDef in one VarGui or combined control of Synths and 

+

Pbinds / EventStreamPlayers.

+

+

args - see aSynthDefName.pVarGui with the exception of Pbind-related args

+

pBefore, pReplace, pAfter, clock, quant, post and trace

+

+


+

aSynthDefName.pfuncPbinds(pBefore, pReplace, pAfter, exclude, excludeGate, excludeDur, excludeLegato, metaKey, useGlobalSpecs, post, trace, num)

+

+

Generate Pbinds with Pfunc pairs derived from a SynthDef name (Symbol / String) and corresponding metadata 

+

resp. global ControlSpecs. Duration and legato pairs are added by default.

+

If an added Pbind pair with key \degree, \note or \midinote is detected, 

+

\freq is excluded automatically. Returns a collection, also for num = 1.

+

+

args - see aSynthDefName.pVarGui with the exception of clock, quant and control-related args

+

ctrBefore, ctrReplace, ctrAfter, durCtr, legatoCtr. 

+

excludeDur - Boolean. Determines if \dur should be excluded from the Pbind. 

+

Also takes a Function of indices that returns a Boolean. Defaults to false.

+

excludeLegato - Boolean. Determines if \legato should be excluded from the Pbind. 

+

Also takes a Function of indices that returns a Boolean. Defaults to false.

+


+


+


+

6.) Save and load

+


+

A VarGui's slider state can be saved via save button and dialog. Loading is straightforward with Synths. You just have to give the correct path and synth arg (which maybe has to be an array).

+


+


+

// change slider positions and save

+


+

\buzz.sVarGui.gui;

+


+

// reload

+


+

VarGui.load("Path_To_XY", "XY", synth: \buzz).gui;

+


+


+

// change slider positions and save

+


+

\buzz.sVarGui(num: 4, metaKey: \basicSpecs).gui(tryColumnNum: 2);

+


+

// reload, synth arg must have corresponding size

+


+

VarGui.load("Path_To_XY", "XY", synth: \buzz ! 4).gui(tryColumnNum: 2);

+


+


+

VarGui only saves slider states, not the Pbind structure (would open a can of worms). So if you had a customized Pbind in the original setup you'd have to pass an appropriate Pbind together with load. This can also be a Pbind other than in the original setup. But if you want to restore you can nearly copy the input of the original cutomization into the pbindmaker method pfuncPbinds (5b).

+


+

// with no customization save and load also works straightforward

+

// change slider positions and save

+


+

\buzz.pVarGui.gui;

+


+

// standard pbind is (re-)autogenerated and fits the variables to be set

+


+

VarGui.load("Path_To_XY", "XY", stream: \buzz).gui;

+


+


+

// only controls are customized, save and load also works straightforward

+

// change slider positions, save and reload

+


+

(

+

[\default, \buzz].pVarGui(

+

(ctrReplace: { |i| var f = (2*i + 1) * 100, d = 0.2, lo = 0.99, hi = 1.01; 

+

[\freq, [f*lo, f*hi, 0, 0, f*rrand(lo,hi)], \dur, [d*lo, d*hi, 0, 0, d*rrand(lo,hi)] ] }, 

+

exclude: \gate, 

+

post: true,

+

num: 4),

+

(ctrReplace: [\freq, [97, 103, \exp, 0, 99], \dur, [0.195, 0.205, 0, 0, 0.2] ])

+

).gui(tryColumnNum: 2, allowEnvirBreak: false)

+

)

+


+

(

+

VarGui.load("Path_To_XY", "XY", stream: \default ! 4 ++ \buzz)

+

.gui(tryColumnNum: 2, allowEnvirBreak: false)

+

)

+


+


+

// change slider positions and save

+


+

(

+

[\buzz, \default].pVarGui((

+

ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ],

+

ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]],

+

pBefore: [\degree, PLseq(\a), \octave, 3], 

+

quant: 0.2

+

),(

+

ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ],

+

ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]],

+

pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), 

+

\octave, Pwhite(5,7) ], 

+

quant: 0.2

+

)

+

).gui(tryColumnNum: 2, allowEnvirBreak: false);

+

)

+


+

// restoring pbind structure, note that pfuncPbinds always returns a collection

+

// and quant arg is separate in VarGui.new and VarGui.load

+


+

(

+

VarGui.load("Path_To_XY", "XY", 

+

stream: 

+

\buzz.pfuncPbinds(pBefore: [\degree, PLseq(\a), \octave, 3]) ++

+

\default.pfuncPbinds(pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), 

+

\octave, Pwhite(5,7) ]),

+

quant: 0.2

+

).gui(tryColumnNum: 2, allowEnvirBreak: false)

+

)

+


+


+


+


+ + diff --git a/Help/VarGui.html b/Help/VarGui.html new file mode 100755 index 0000000..5acfe5c --- /dev/null +++ b/Help/VarGui.html @@ -0,0 +1,1561 @@ + + + + + + + + + + + +

VarGui slider / player gui to set envir variables and synth controllers and play synths, event patterns and tasks

+


+

Part of: miSCellaneous

+


+

Inherits from: Object

+


+

SC setups may contain discrete and continuous control, e.g. using combinations of Pbinds, Tasks and Synths. There are many possible ways of interaction between such elements, sometimes there is the alternative to control things by server or language (e.g. Pbinds versus Demand Ugens) but often one needs to have both. VarGui is a multi purpose slider and player GUI, originally intended for indentifying parameters to be reused in other setups.

+

Pbinds and Tasks can easily refer to environmental variables - in case of Pbinds e.g. via Pfunc, Plazy, Pcollect, but more conveniently via the dynamic scope PLx suite - so VarGui can control environmental variables and synth controllers. For basic principles of using event patterns with functional code and the related scoping features see Event patterns and Functions. VarGui was not intended for performance, however (since miSCellaneous v0.4) it includes a player section. Players can be used in different (reset) modes, states of synths and streams are reflected by colors, it also works with wslib slider classes (Example 8). For quick GUI generation using SynthDef metadata for controlspecs and / or automatic Pbind builds see VarGui shortcut builds. As both VarGui help files are quite full of details, a more general overview, including some exercises, is given in Introduction to miSCellaneous.

+


+


+

See also: VarGui shortcut builds, Introduction to miSCellaneous, PLx suite, Event patterns and LFOs, Event patterns and Functions, Buffer Granulation, Live Granulation, HS with VarGui

+


+


+

Some Important Issues Regarding VarGui

+


+

VarGui allows to choose SynthDefs or Synths, Events patterns or EventStreamPlayers and Task functions or Tasks as input. It is recommended to take the more general objects (SynthDefs, Event patterns, Task functions) as then derived Synths, EventStreamPlayers and Tasks are newly generated and the latter are run in newly generated Environments. If you follow this it is very unlikely to accidentally break gui representation of data (though it's not strict MVC paradigm).

+


+

On the other hand there are special cases when you might want to pass Synth objects / synth nodes, Tasks or EventStreamPlayers directly (e.g. HS with VarGui). Then a bit more care has to be taken as, although a VarGui instance doesn't allow to poll more than one GUI window from it, nothing prevents you from refering to identical Synth objects / synth nodes, Tasks, EventsStreamPlayers or environmental variables with different VarGui instances. This is not recommended as, obviously, a possible source of confusion.

+


+

If you are passing a Synth directly and moreover its SynthDef is not known to SynthDescLib setting a single component of an arrayed control also causes setting of all components below (no other choice at the moment, however, a very special case). 

+


+

GUI specific:

+


+

With miSCellaneous v0.16 (March 2017) backwards compatibility with Cocoa and SwingOSC is no longer supported, now cross-platform Qt is standard. VarGui was originally written with Cocoa as reference, though restrcitions on Qt are minor. 

+


+

1) With Qt mouseDown is the hardcoded mode of player action, which anyway could be regarded as standard usage.

+


+

2) Moving several sliders in parallel (see Example 1c) works on all platforms and with wslib sliders. 

+

+

3) Combined slider movement with modifier keys differs in the necessary order of key pressing and mouse clicking.

+

In Qt you can (and with the Cmd modifier involved you have to) press thereafter.

+


+

4) With EZSlider you can jump to a certain slider position by clicking at an arbitrary position in the slider field.

+

With wslib sliders you can choose modes \jump and \move (Example 8). 

+


+

5) Combined synth / stream player button actions with Caps-lock are currently not working with Qt.

+

+

+


+

You can list styles by

+


+

GUI.availableStyles

+


+

and set with

+


+

GUI.style = \myFavoriteStyle

+


+


+

Creation / Class Methods

+


+

*new (varCtr, synthCtr, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, assumePlaying, assumeRunning, assumeEnded, server)

+

+

Create a new VarGui object, which holds control specifications.

+

+

varCtr - specPairs or a collection of specPairs, where

+

specPairs is a collection of the form [ key, spec, ...  ] where

+

key is the symbol of the environmental variable to be set and

+

spec must be one of those:

+

(a) Collection of the form [ minval, maxval, warp, step, default ], 

+

defining the corresponding ControlSpec, or a collection of specs of this form

+

for an arrayed control if the environmental variable should have the value 

+

of a collection itself. step is used for the derivation of slider step size.

+

(b) Symbol refering to a ControlSpec globally stored in Spec.specs

+

or a collection thereof for arrayed control.

+

ControlSpec.step is used for the derivation of slider step size.

+

(c) SimpleNumber for a dummy slider with fixed value.

+

If specPairs or single components of a collection of specPairs are nil and the corresponding

+

stream arg is a Symbol or String pointing to a SynthDef, it will be tried to derive 

+

controls from corresponding SynthDef metadata resp. global ControlSpecs 

+

(see VarGui shortcut builds).

+

+

Variables are set in environments that are either given implicitely (1) or explicitely (2):

+

+

(1) by eventstream players / tasks passed to stream - they are already bound to an

+

environment - or newly generated together with eventstream players or tasks from 

+

patterns or functions passed to stream. 

+

+

(2) by envir. This allows setting of variables in Environments in case of absent stream players.

+

+

From explicit or implicit envir input an ordered collection of non-identical environments is derived,

+

which, without one of the above infos, will consist of currentEnvironment only.

+

+

If varCtr is already grouped as a collection of specPairs then variables from i-th specPairs will be set

+

in the i-th environment of the derived collection. 

+

If varCtr is given as a flat collection and specPairs contains no multiple keys then variables are set

+

in the first resp. only environment in question. 

+

If varCtr is given as a flat collection and specPairs contains multiple keys then varEnvirGroups

+

is needed to map variables to environments (Example 5a).

+

Note that the i-th environment means the i-th non-identical environment, not necessarily

+

(in the case of environments implicitely given by eventstream players / tasks) the environment

+

of the i-th stream.

+

Defaults to nil.

+

synthCtr - specPairs or a collection of specPairs, where

+

specPairs may be nil or a collection of the form [ key, spec, ...  ] where

+

key is the symbol of the control arg to be set and

+

spec must be one of those:

+

(a) Collection of the form [ minval, maxval, warp, step, default ], 

+

defining the corresponding ControlSpec, or a collection of specs of this form

+

for an arrayed control. step is used for the derivation of slider step size.

+

(b) Symbol refering to a ControlSpec globally stored in Spec.specs

+

or a collection thereof for arrayed control.

+

ControlSpec.step is used for the derivation of slider step size.

+

(c) SimpleNumber for a dummy slider with fixed value.

+

If specPairs or single components of a collection of specPairs are nil, it will be tried to

+

derive controls from SynthDef metadata resp. global ControlSpecs (see VarGui shortcut builds).

+

+

If synthCtr is already grouped as a collection of specPairs then controls from i-th specPairs will be used

+

for setting the i-th synth. 

+

If synthCtr is given as a flat collection and specPairs contains no multiple keys then controls will be used

+

for setting the only synth in question.

+

If synthCtr is given as a flat collection and specPairs contains multiple keys then synthCtrGroups

+

is needed to map synth controls to synths (Example 5b).

+

Defaults to nil.

+

stream - Expects Pattern, EventStreamPlayer, Function, Task or a collection thereof,

+

determining the number of stream players.

+

Patterns / Functions are used as templates for EventStreamPlayers / Tasks in 

+

environments generated at init time. If stream is unequal nil variables given by 

+

varCtr will be set in the environments derived from it.

+

A Symbol or String pointing to a SynthDef causes automatic generation of a Pbind. 

+

If varCtr resp. the corresponding varCtr component is nil it will be tried to derive 

+

Pbind controls from corresponding SynthDef metadata resp. global ControlSpecs 

+

(see VarGui shortcut builds).

+

Size of stream must at least equal and may exceed the number of varCtr groups,

+

which (see above) may be given by varCtr itself (if a grouped collection of specPairs)

+

or varCtrGroups. 

+

Correspondence between environments of variables and eventstream / task players 

+

is optionally indicated in the GUI - however the user is responsible for defining 

+

patterns and task functions that really involve the variables to be set !

+

Defaults to nil.

+

synth - Input to which synth controls are mapped. Expects Symbol refering to a SynthDef, 

+

Synth, nodeID or collection thereof. 

+

Size of synth must at least equal and may exceed the number of synthCtr groups,

+

which (see above) may be given by synthCtr itself (if a grouped collection of specPairs)

+

or synthCtrGroups. 

+

It is recommended to refer to "known" SynthDefs (SynthDescLib), best by 

+

passing Symbols or also registered Synths, otherwise the correct synth state must be given

+

explicitely by assumePlaying, assumeRunning resp. assumeEnded, which is a nearby

+

source of error and confusion.

+

Defaults to nil.

+

clock -  TempoClock, nil or collection thereof for playing streams.

+

Passed clocks have precedence over implicitely given clocks (running eventstream players 

+

or tasks as stream input) in case of resuming from pause state.

+

Defaults to the default TempoClock.

+

quant -  Quant, Float, nil or collection thereof used as quant data for playing streams.

+

Will be used in case of resuming from pause state for running 

+

eventstream players or tasks given as stream input.

+

Defaults to Quant.default (none).

+

varEnvirGroups - SequenceableCollection of Collections of Integer.

+

Expects ordered partition of the number N of specPairs given to varCtr as a flat collection, 

+

also counting multiple occurences, thus defining a mapping: variable keys -> environments.

+

Must be a valid partition of N (taking all integers i < N, 0 included, each only once). 

+

Its size must not exceed the number of implicitely or explicitely given environments (see varCtr).

+

E.g. for 3 environments and 6 variables [[2], [0,1,5], [4,3]] would be valid.

+

Defaults to nil.

+

envir - SequenceableCollection of Environments.

+

Environments to be used for variable setting in case of absent stream players, only admissible if stream is nil.

+

Defaults to nil.

+

synthCtrGroups - SequenceableCollection of Collections of Integer.

+

Expects ordered partition of the number N of specPairs given to synthCtr as a flat collection,

+

also counting multiple occurences, thus defining a mapping: synth control keys -> environments.

+

Must be a valid partition of N (taking all integers i < N, 0 included, each only once). 

+

Its size must not exceed the size of synth.

+

Defaults to nil.

+

assumePlaying - Boolean, nil or collection thereof, then size must equal the number of synths given

+

by synth or synthCtr. Player state information for (unregistered) synths or nodeIDs, 

+

booleans are not accepted if corresponding items in synth are instances of Symbol or String.

+

Defaults to nil.

+

assumeRunning - Boolean, nil or collection thereof, then size must equal the number of synths given

+

by synth or synthCtr. Player state information for (unregistered) synths or nodeIDs, 

+

booleans are not accepted if corresponding items in synth are instances of Symbol or String.

+

Defaults to nil.

+

assumeEnded - Boolean, nil or collection thereof, then size must equal the number of synths given

+

by synth or synthCtr. Player state information for (unregistered) synths or nodeIDs, 

+

booleans are not accepted if corresponding items in synth are instances of Symbol or String.

+

Defaults to nil.

+

server - Server. The server to send node messages for synth control. Doesn't affect Pbinds

+

as server can be determined by their definition. Defaults to the default server.

+

+

+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+

+

+

// Pbind defined with variable to be controlled while playing

+

// Pfunc's function is evaluated at playtime of each Event and gets

+

// the value of the variable ~midi in the environment in which the EventStreamPlayer will be playing

+

+

p = Pbind(\midinote, Pfunc { ~midi } + Pseq([0, 3, 5, 7], inf), \dur, 0.2) 

+

+

+

// VarGui to set this variable.

+

// As a pattern is given as stream arg the derived EventStreamPlayer will run in a new environment

+

// which is generated at VarGui init time

+

+

v = VarGui([\midi, [50, 70, \lin, 1, 55]], stream: p).gui;

+

+

+

// Try out basic slider and player functionality

+

+

// Playing: 

+

+

attachments/VarGui/player_1.png

+

+

// Background of player button lightening yellow. Functionality of the reset button depends

+

// on the active mode. The green background of the reset mode button indicates that the reset button

+

// will reset while playing and its background will flash yellow.

+

+

// The text field on the right side indicates whether an eventstream player or a task is playing,

+

// that on the left side shows the index of the environment in which the stream is playing.

+

// This is mainly useful if more stream players and variables of same names in different environments

+

// are involved - below the players there is a toggle button to indicate the envir index in slider name fields.

+

+

// Pausing: 

+

+

attachments/VarGui/player_2.png

+

+

// Now pushing the play button will resume the stream where it has been paused,

+

// pushing the reset button (if the reset mode button has green background) 

+

// will reset and play the stream.

+

+

// Pausing and reset: 

+


+

attachments/VarGui/player_3.png

+

+

// This state can be reached from playing, pausing or ended stream when pushing the reset button under 

+

// reset mode pause (orange background). Now only the play button can play the (reset) stream

+

+

// Stream has ended: 

+


+

attachments/VarGui/player_4.png

+

+

// E.g. if an eventstream player has encountered nil, reset button's background will become red.

+

// Now it needs the reset button to go on and its action - pause or play - depends on the active mode. 

+

+

+

//////////////////////////////////////////////////// 

+


+


+

// synth definition with raising frequency

+

+

(

+

SynthDef(\synth_0, { |devFactor = 0.1, devFreq = 10, amp = 0.1|

+

var freq = XLine.kr(400, 1200, 10); 

+

Out.ar(0, SinOsc.ar(SinOsc.ar(devFreq, 0, devFactor * freq, freq), mul: amp).dup(2) * EnvGate.new) 

+

}).add;

+

)

+

+

// VarGui to play synth of above definition and set synth args, 

+

// Player functionality with different stop / renew modes.

+

// Notification must be on.

+

// Note that pause, stop and resume actions cause sending of run / free messages, thus possibly audible clicks.

+

// To avoid that work with amp = 0 or use a gated envelope and a gate control slider with only values 0 and 1 or

+

// use Synths of limited duration as in Example (2)

+

+

(

+

VarGui(

+

synthCtr: [\devFactor, [0, 0.99, \lin, 0.01, 0.5], 

+

\devFreq, [1, 100, \lin, 0.1, 70],

+

\amp, [0, 0.3, \lin, 0.001, 0.1]], 

+

synth: \synth_0).gui;

+

)

+

+

// Latency options (buttons and boxes below the player section):

+

// bundle latency of synth player actions can be set to nil, a custom value (button abbrieviation c) or 

+

// global server latency (abbr. s), these two values can be set in the boxes below 

+

// settings can be used to sync synth and stream players, if both contained in a GUI

+

+


+

// Synth players work similar as stream players, but there are more options.

+

// There is an addtional stop mode button that determines how and if 

+

// renewing (creating new synth nodes of same definition) is handled.

+

+

// If, as above, a synth is given by a reference to a known SynthDef

+

// VarGui will start with a basicNew Synth object, indicated by 

+

// white background of the synth's number field:

+

+

attachments/VarGui/player_5.png

+

+

// Rate type (audio) is indicated in the field on the right.

+

// From this state a node on the server will be created by pause (newPaused) or play (new):

+

+

attachments/VarGui/player_6.png

+

+

// Now playing and pausing work as usual.

+

// The red and blue background of the stop mode button indicates that the red stop button

+

// will become a blue renew button as soon as the Synth is stopped (node freed).

+

+

// In addition to the renew modes play (green) and pause (orange) there is also a

+

// renew mode basic new (white):

+

+

attachments/VarGui/player_7.png

+

+

+

// If stop mode is set to renew (blue) the renew button will never change its function.

+

// Under renew mode play (green) every renew will free a Synth and immediately start a new 

+

// (background flashing yellow):

+

+

attachments/VarGui/player_8.png

+

+

+

// If stop mode is set to stop (red background), the stop / renew button will change to red:

+

+

attachments/VarGui/player_9.png

+

+

// The renew mode button loses its function (greyed out) and stopping just frees the Synth:

+

+

attachments/VarGui/player_10.png

+

+

// Now stop mode would have to be changed in order to play a new Synth.

+

+

+


+

// General functionality

+

+

+

attachments/VarGui/main_buttons.png

+

+

+

// The Update Button

+

+

// Unless the VarGui window was generated with option updateNow set to false

+

// (which could be desired e.g. for a start with Synth defaults), 

+

// variables and synth controls are set to slider values at gui init time,

+

// normally updating is not required. 

+

// As for most uses VarGui would generate new separate environments for

+

// passed event patterns and task functions, there is no update mechanism implemented

+

// if these variables would be changed otherwise.

+

// Analagously controls of Synths played (and probably just yet generated) by a VarGui 

+

// player could of course be set by means other than a VarGui slider action.

+

+

// Anyway both situations seem to be exceptional (you could hardly do so just by an oversight), 

+

// though you can update to all slider values manually.

+

+

+

// The Save Button

+

+

// Opens a dialog to save the current slider state as an array of 4 items:

+

// varCtr as flattened array of specPairs, synthCtr as flattened array of specPairs, 

+

// varEnvirGroups, synthCtrGroups (which are only stored as groupings in case of multiple key occurences, nil optherwise)

+

+

// Player data and synth information is not stored.

+

// For loading from a file you would have to pass this (see the load method below)

+

+

+

// The Stop Button

+

+

// Free all synths and stop all streams.

+

// You can also use modifier keys for stopping groups of players,

+

// e.g. Shift-click on a stream players's pause button to stop all streams.

+

// Freeing all synths in the same way only works if all synth players can be stopped by their stop buttons at this time.

+

+

+


+

*load (pathname, filename, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, assumePlaying, assumeRunning, assumeEnded, server)

+

+

Create a VarGui, that loads a stored slider state (varCtr and synthCtr data) from the specified file,

+

which has probably been saved before via dialog. See also  VarGui shortcut builds, Ch. 6.

+

+

pathname - Pathname string.

+

filename - Filename string.

+

other args - see *new

+

+

+

*load_old (pathname, filename, stream, synth, clock, quant, varEnvirGroups, envir, synthCtrGroups, assumePlaying, assumeRunning, assumeEnded, server)

+

+

Create a VarGui, that loads a stored slider state from the specified file.

+

This is for loading slider states that have been saved with miSCellaneous v0.3 or earlier, thus ignoring the synth control slider label.

+

Though old code examples will not necessarily work after just replacing load by load_old as other conventions have changed too.

+

Maybe you'd also have to change synth and stream (former players) or add assumePlaying and assumeRunning args.

+

+

pathname - Pathname string.

+

filename - Filename string.

+

other args - see *new

+


+

+

Creating a gui from the VarGui object

+

+


+

gui (sliderHeight, sliderWidth, labelWidth, numberWidth, sliderType, sliderMode, playerHeight, 

+

precisionSpan, stepEqualZeroDiv, tryColumnNum, allowSynthsBreak, allowVarsBreak, 

+

allowSynthBreak, allowArrayBreak, allowEnvirBreak, minPartitionSize, 

+

sliderPriority, playerPriority, streamPlayerGroups, synthPlayerGroups, comboPlayerGroups, 

+

font, colorsLo, colorsHi, colorDeviation, ctrButtonGreyCenter, ctrButtonGreyDev, greyMode, name, updateNow,

+

sliderFontHeight, playerFontHeight, maxWindowWidth, maxWindowHeight)

+

+

Create a gui window.

+

+

sliderHeight - Gui slider height. Defaults to 18. 

+

sliderWidth - Gui slider width. Depends on number of columns if not given explicitely. 

+

labelWidth - Slider label width. Default depends on platform and gui scheme (70 or 75).  

+

numberWidth - Slider numberbox width. Default depends on platform and gui scheme (40 or 45).  

+

sliderType - One of the Symbols \standard, \smooth, \round. Both latter refer to EZSmoothSlider

+

and  EZRoundSlider from wslib (Quark), which needs to be installed for that choice. 

+

See Example 8. Defaults to \standard. 

+

sliderMode - One of the Symbols \jump, \move. 

+

Only relevant in case of sliderType \smooth or \round. 

+

Determines behaviour if slider field is clicked apart from the knob.  

+

See Example 8. Defaults to \jump. 

+

playerHeight - Gui player height. Defaults to 18. 

+

precisionSpan - Integer. Precision span to be regarded for representation of controlspec step.

+

See Example 9. Defaults to 10. 

+

stepEqualZeroDiv - Integer. Division to be assumed if controlspec step equals 0.

+

See Example 9. Defaults to 100. 

+

tryColumnNum - Integer. VarGui tries to arrange variable and control sliders in this number of columns

+

if possible under the restrictions of maxWindowWidth, sliderWidth, minPartitionSize and the following allow options.

+

Internally a list of possible break indices is derived and then a partition as equal in size as possible is searched for.

+

See Examples 5a, 5b.

+

Defaults to 1.

+

allowSynthsBreak - Boolean. Determines if all synth control sliders should be grouped within one column.

+

Defaults to true. 

+

allowVarsBreak - Boolean. Determines if all variable control sliders should be grouped within one column.

+

Defaults to true. 

+

allowSynthBreak - Boolean. Determines if control sliders of one synth should be grouped within one column.

+

Setting false only has an effect if synth controls are ordered in connected groups.

+

Defaults to true. 

+

allowArrayBreak - Boolean. Determines if control sliders of an arrayed control (variable or synth) should be 

+

grouped within one column. Defaults to true. 

+

allowEnvirBreak - Boolean. Determines if control sliders of one environment should be grouped within one column.

+

Setting false only has an effect if environmental variables are ordered in connected groups.

+

Defaults to true. 

+

minPartitionSize - Integer. Determines the minimum number of sliders of same type that may be grouped 

+

in a different column. Defaults to 0. 

+

sliderPriority - Symbol \var or \synth. Determines if variable or synth control sliders should be listed first.

+

Defaults to \var. 

+

playerPriority - Symbol \stream or \synth. Determines if stream or synth players should be listed first.

+

Defaults to \stream. 

+

streamPlayerGroups - Grouping of number of stream players (E.g. [[0], [1,2]] is a valid grouping of 3 players). 

+

Defines control group for modifier option of stream playing. 

+

Defaults to the grouping of all streamPlayers.

+

synthPlayerGroups - Grouping of number of synth players. 

+

Defines control group for modifier option of synth playing.

+

Defaults to the grouping of all synthPlayers.

+

comboPlayerGroups - ***currently not working*** 

+

Grouping of number of synth and stream players. 

+

Defines control group for modifier option of combined synth and stream playing.

+

Defaults to the grouping of all synth- and streamPlayers.

+

font - GUI font as String. Defaults to "Helvetica".

+

colorsLo - Low RGB value for color space, in which distinct slider colors for logical groups (synth, environment) 

+

and background are chosen by random. Must be between 0 and 1. Defaults to 0.25 in color mode 

+

and 0.4 in grey mode. 

+

colorsHi - Hi RGB value for color space, in which distinct slider colors for logical groups (synth, environment) 

+

and background are chosen by random. Must be between 0 and 1. Defaults to 0.7 in color mode 

+

and 0.6 in grey mode. 

+

colorDeviation - Nonnegative SimpleNumber. Determines the maximum amount of color deviation within a 

+

logical slider group (synth, environment). Within the maximum deviation distinct colors are ramdomly chosen, 

+

but arrayed controls get the same color. Defaults to 0.12 in color mode and 0 in grey mode.

+

ctrButtonGreyCenter - Float between 0 and 1. Determines the grey center from which button colors deviate 

+

by the amount of ctrButtonGreyDev. Defaults to 0.5. 

+

ctrButtonGreyDev - Float between 0 and 1. Determines the intensity of button colors deviating from

+

ctrButtonGreyCenter. Defaults to 0.8 in color mode and 0.65 in grey mode.

+

greyMode - Boolean. Determines if color or grey mode is chosen. Defaults to false.

+

varColorGroups - Grouping of colors of variable control sliders. Overrules automatic color grouping.

+

All indices < n (number of sliders) must occur exactly once. E.g. [[0], [1,2]] would be valid for n = 3.

+

See Example 7.

+

synthColorGroups - Grouping of colors of synth control sliders. Overrules automatic color grouping.

+

All indices < n (number of sliders) must occur exactly once. E.g. [[0], [1,2]] would be valid for n = 3.

+

See Example 7.

+

name - Symbol or String. Name to be displayed in the GUI window title bar. If not given explicitely types of

+

controls and players are indicated.

+

updateNow  - Boolean. Determines if controls and variables should be set to slider values at GUI build time.

+

To keep sliders in sync with control this is done by default - however there may be cases when it is

+

desirable to start with other values, e.g. the synth's defaults. If set to false slider values will not be set

+

before the slider is moved or before all values are set by the update method or the corresponding button.  

+

sliderFontHeight - Float. Adapts to sliderHeight if value nil is given (default). 

+

Normally this doesn't have to be set except with very small sliderHeight and/or certain fonts. 

+

playerFontHeight - Float. Defaults to 12. 

+

maxWindowWidth - Float. Defaults to 1500.

+

maxWindowHeight - Float. Defaults to 700.

+

+

+

// SynthDef from above, number of synth players multiplied by expanding single control

+

// For multiple slider and player button control see the modifier options explained in Example 1c.

+

+

(

+

v = VarGui(

+

synthCtr: [\devFactor, [0, 0.99, \lin, 0.01, 0.5], 

+

\devFreq, [1, 100, \lin, 0.1, 70],

+

\amp, [0, 0.2, \lin, 0.001, 0.02]] ! 6, 

+

synth: \synth_0 ! 6);

+

v.gui;

+

)

+


+

// GUI appearance customization:

+

// close window (only one window per VarGui instance allowed) and try again with same or other color options 

+

+

v.gui;

+

+

+

//

+

+

v.gui(colorDeviation: 0, colorsLo: 0.4, colorsHi: 0.9);

+


+


+

//

+

+

v.gui(greyMode: true);

+


+


+

// force slider arrangement in 2 columns, controls of each synth should only be in one column

+

+

v.gui(colorDeviation: 0, tryColumnNum: 2, allowSynthBreak: false);

+


+


+

+

// you can save a slider state snapshot by button / dialog to the file "XY",

+

// only slider states (flattened spacPair collections) and groupings are stored, 

+

// you have to pass synth data with load 

+


+

VarGui.load("PathToXY", "XY", synth: \synth_0 ! 6).gui;

+

+


+

update

+

+

Update variables and controllers to current slider values. Like update button action.

+

Unless the VarGui window was generated with option updateNow set to false, 

+

variables and controllers are immediately set to slider values and normally updating is not required. 

+

+


+

updateVarSliders(key, varNum, val, indexOffset, updateNow)

+

+

Update variable sliders.

+

+

key - Variable name given as Symbol.  

+

varNum - Integer. Index of variable occurence in given varCtr. Defaults to 0.

+

val - Float. May also be collection, then a sequence of variable sliders is set. 

+

indexOffset - Integer. Updating will start at this index in case key refers to arrayed control. Defaults to 0.

+

updateNow - Boolean. Determines if variables should immediately be updated with sliders. Defaults to true.

+

+


+

updateSynthSliders(key, synthNum, val, indexOffset, updateNow)

+

+

Update synth sliders.

+

+

key - Synth control name given as Symbol.  

+

synthNum - Integer. Index of synth in given synthCtr. Defaults to 0.

+

val - Float. Maybe also be collection, then a sequence of synth sliders is set. 

+

indexOffset - Integer. Updating will start at this index in case key refers to arrayed control. Defaults to 0.

+

updateNow - Boolean. Determines if synth controls should immediately be updated with sliders. Defaults to true.

+


+

+

font(font, sliderFontHeight, playerFontHeight)

+

+

Set GUI font.

+

+

font - String. Defaults to "Helvetica".

+

sliderFontHeight - Integer. Defaults to 12.

+

playerFontHeight - Integer. Defaults to 12.

+


+

+

addSliderAction(function, type, index, envir)

+

+

Add an action to be evaluated as sliderView's mouseUpAction.

+

+

function - Function.

+

type - Slider type, expects \var or \synth. Defaults to \var.

+

index - Integer. Slider index of given type.

+

envir - Environment where function should be evaluated. If not specified and type equals \var 

+

the environment associated with the variable will be taken.

+

+


+

startMIDIlearn

+

+

Start learining mode for receiving MIDI cc messages for slider control, see Ex.10.

+


+


+


+

stopMIDIlearn

+

+

Stop learining mode for receiving MIDI cc messages for slider control, see Ex.10.

+


+


+


+

Example 1a:   step sequencer

+


+


+

(

+

s = Server.local;

+

Server.default = s;

+

s.boot;

+

)

+


+


+

// There are different ways to read a sequence of values from a 

+

// settable array assigned to an envir variable.

+

// PLseq is convenient, for a comparison with Plazy, Pfunc etc. see PLx suite

+


+

// In all cases the EventStreamPlayer can be played in an 

+

// arbitrary environment, from which ~seq will be taken.

+

// This holds true for Patterns with functional code like Pfunc

+

// and also for PLseq, the latter has an envir arg 

+

// which defaults to \current.

+


+

// Note that all PLx Patterns default to repeats = inf,

+

// ListPatterns as Pseq default to repeats = 1.

+


+


+

(

+

// OffsetOut for exact timing

+


+

SynthDef(\synth_1a, { |freq = 400, preAmp = 5, amp = 0.1|

+

var src = SinOsc.ar(freq, 0, mul: preAmp).tanh ! 2;

+

OffsetOut.ar(0, src * amp * EnvGen.ar(Env.perc, doneAction: 2))

+

}).add;

+


+

p = Pbind(

+

\instrument, \synth_1a,

+

\preAmp, PL(\preAmp),  // or Pfunc { ~preAmp }

+

\amp, PL(\amp), // or Pfunc { ~amp }

+

\midinote, PLseq(\seq) + PL(\seqAdd), 

+

\dur, 0.2

+

);

+


+

// ~seq will be set and read in the new Environment, which will be generated at VarGui init time.

+


+

~specPairs = [\seq, [36, 60, \lin, 1, 36] ! 5, 

+

\seqAdd, [0, 12, \lin, 1, 0],

+

\amp, [0, 0.3, \lin, 0.01, 0.1],

+

\preAmp, [5, 50, \lin, 0.01, 20]];

+


+

v = VarGui(~specPairs, stream: p).gui;

+

)

+


+


+


+

Example 1b:   step sequencer with MIDI

+


+


+

// connect a MIDI device, allNotesOff with CmdPeriod useful

+


+

(

+

MIDIClient.init;

+

m = MIDIOut(0);

+

g = { 16.do({|i| m.allNotesOff(i) }) };

+

CmdPeriod.add(g); 

+


+


+

p = Pbind(

+

\type, \midi,

+

\midiout, m, 

+

\chan, 0,

+

+

\amp, PL(\amp),

+

\midinote, PLseq(\seq) + PL(\seqAdd), 

+

\dur, 0.2

+

);

+

)

+


+

(

+

v = VarGui([\seq, [36, 60, \lin, 1, 36] ! 5, 

+

\seqAdd, [0, 12, \lin, 1, 0],

+

\amp, [0, 1, \lin, 0.01, 0.8]],

+

stream: p).gui;

+

)

+


+

// remove if not needed anymore

+


+

CmdPeriod.remove(g); 

+


+


+


+

Example 1c:  more step sequencers, quantization, slider modifiers 

+


+


+

// SynthDef from (1a)

+

// four players from a Pbind, four varCtr specifications with shifted range

+


+

(

+

p = Pbind(

+

\instrument, \synth_1a,

+

\preAmp, PL(\preAmp), 

+

\amp, PL(\amp), 

+

\midinote, PLseq(\seq) + PL(\seqAdd), 

+

\dur, 0.2

+

);

+


+

~spec = 4.collect { |i| [\seq, [12*i + 24, 12*i + 48, \lin, 1, 24*i + 36] ! 5, 

+

\seqAdd, [0, 12, \lin, 1, 0],

+

\amp, [0, 0.15, \lin, 0.01, 0.07 - (0.01 * i)],

+

\preAmp, [5, 50, \lin, 0.01, 20]] };

+

)

+

+

// run all players in sync by passing a quant arg

+


+

+

v = VarGui(~spec, stream: p!4, quant: 0.2).gui(tryColumnNum: 2, streamPlayerGroups: [[0,3], [1,2]]);

+


+

// EventStreamPlayers derived from Pbind are run in four newly generated environments,

+

// variables, as their names are passed four times in spec, are automatically set in these Environments in order.

+

// Envir index display can be toggled with the button on the right.  

+


+

// get envirs:

+


+

v.envirs;

+


+


+

// Try slider actions with modifier keys

+


+


+

// In Qt you can press modifier keys before and thereafter.

+

// Caps-lock is currently replaced by Cmd,

+

// With the Cmd modifier involved you *have* to press thereafter.

+


+

// Modifiers allow to control groups of sliders, values in other sliders are clipped to the according range.

+

// The following rules apply to synth and var control sliders separately,

+

// combined synth and var controls of same name work with Cmd elsewise (Ex.2).

+


+

// Shift: within an arrayed control all sliders below are set to the handled value or clipped.

+

// Shift + Ctrl: within an arrayed control all sliders above are set to the handled value or clipped.

+


+

// Alt: controls of same name (in different envirs or different synths) are set to the handled value or clipped.

+

// Alt + Shift, Alt + Shift + Ctrl: Accordingly for arrayed controls of same name. 

+


+

// Modifier keys also apply to synth and stream player actions,

+

// the following to synth OR stream player combinations either:

+


+

// Shift: button action with all players 

+

// Shift + Ctrl: button action with all players of this state

+

// Shift + Alt: button action with all players of this group (if synthPlayerGroups / streamPlayerGroups was defined)

+

// Shift + Ctrl + Alt: button action with all players of this state and group ( --- " --- )

+


+


+

Example 1d:   step sequencer, stream players in same environment 

+


+


+

// You can try to benefit from eventstream players having variables in common.

+

// SynthDef from (1a), second Pbind derived from p without pitch offset as parallel pattern 

+


+

(

+

p = Pbind(

+

\instrument, \synth_1a,

+

\preAmp, PL(\preAmp), 

+

\amp, PL(\amp), 

+

\midinote, PLseq(\seq) + PL(\seqAdd), 

+

\dur, 0.2

+

);

+


+

q = Pbindf(p, \midinote, PLseq(\seq));

+


+

v = VarGui([\seq, { [48, 84, \lin, 1, rrand(48, 84)] } ! 5, 

+

\seqAdd, [0, 12, \lin, 1, 7],

+

\amp, [0, 0.3, \lin, 0.01, 0.07],

+

\preAmp, [5, 50, \lin, 0.01, 20]],

+

stream: [q,p].collect(_.asESP),

+

// so currentEnvironment at build time is given implicitely 

+

// by both ESPs and used for setting

+

quant: 1

+

// ensures that players, also if started separately 

+

// for the first time, will play the sequence in sync

+

).gui;

+

)

+


+

// stopping and resuming of a single player may break parallelism 

+

// Shift-clicked reset syncs again

+


+


+


+

Example 1e:   step sequencer and replacements with PLx

+


+


+

(

+

// SynthDef from (1a)

+


+

// Pbind with PL as placeholder for pitch patterns

+

// master VarGui with player

+

// start and set seq

+


+


+

p = Pbind(

+

\instrument, \synth_1a,

+

\preAmp, PL(\preAmp), 

+

\amp, PL(\amp), 

+

\midinote, PL(\a) + PL(\seqAdd), 

+

\dur, 0.2

+

);

+


+


+

// ESP as stream arg: variables will be read from (build time) current Environment.

+


+

~basePat = PLseq(\seq);

+

~a = ~basePat;

+


+

v = VarGui([\seq, [36, 60, \lin, 1, 36] ! 5,

+

\seqAdd, [0, 12, \lin, 1, 0],

+

\amp, [0, 0.1, \lin, 0.001, 0.05],

+

\preAmp, [5, 50, \lin, 0.01, 20]],

+

stream: p.asESP).gui(name: \seq); 

+


+

// control spec array builder for midi range 

+


+

~pitchSpec = { |key = \seq, default = 60, step = 1, lo = 24, hi = 96|

+

var spec = default.asArray.collect([lo, hi, \lin, step, _]);

+

[key, (spec.size == 1).if { spec.flatten }{ spec }];

+

};

+

)

+


+


+

// replace while playing:

+


+

// chord sequence 

+


+

( 

+

~chordPat = PLseq(\seq) + [0, 7];

+

~a = ~chordPat;

+

)

+


+


+

// random sequence with new VarGui for lead voice bounds

+


+

(

+

VarGui(~pitchSpec.(\b, [75, 85], 0.01)).gui(name: \random);

+


+

~randPat = Pfunc { rrand(~b[0], ~b[1]) } + [0, -13.3, -17.7];

+

~a = ~randPat;

+

)

+


+

// accumulation sequence with new VarGui 

+


+

(

+

VarGui(~pitchSpec.(\accum, { rrand(40,80) }!7 )).gui(name: \accum);

+


+

~accPat = Ptuple( [ PL(\accum), PLseq((0..6)) ] ).collect { |x| x[0].keep(x[1]) - x[1] };

+

~a = ~accPat;

+

)

+


+


+

// switch between PLs and set values in VarGui windows

+


+


+

~a = ~basePat;

+


+

~a = ~chordPat;

+


+

~a = ~randPat;

+


+

~a = ~accPat;

+


+


+


+

Example 2:   stream players and synths in one VarGui 

+


+


+

(

+

// Pbind with default synth

+

// ~freq can be a collection, then pitch or chord are shifted by ~freqFac,

+

// ascending (~step > 0) or descending (~step < 0) groups of 4 items

+


+

p = Pbind(

+

\dur, 0.4,

+

\amp, PL(\amp),

+

\freq, PL(\step) ** PLseq((0..3)) * PL(\freq) * PL(\freqFac)    

+

);

+

+

// Synth producing an ascending line, it ends as envelope params are defined,

+

// end notifications will be reflected in the VarGui

+

+

SynthDef(\synth_2, { |out = 0, freq = #[600, 700, 900, 1000], freqFac = 1, 

+

amp = 0.1, ampFac = 0.5, preAmp = 5, attTime = 0.2, relTime = 2, susTime = 6|

+

var src = SinOsc.ar(freq * XLine.kr(freqFac/2, freqFac, attTime + susTime), 0, mul: preAmp).tanh ! 2;

+

Out.ar(0, src * amp * ampFac * EnvGen.ar(Env.linen(attTime, susTime, relTime), doneAction: 2))

+

}).add;

+

)

+


+

// Try multiple slider movements with modifier keys as described in (1c).

+

// As synth args and variables are identically named they can be controlled

+

// with linked slider movements using Cmd.

+


+

// Accordingly stream and synth player buttons can also be pressed in parallel 

+


+

(

+

v = VarGui([\freq, [600, 700, 900, 1000].collect([400, 1200, \lin, 0.01, _]),

+

\freqFac, [0.25, 1.25, \lin, 0.01, 1],

+

\amp, [0.0, 0.1, \lin, 0.001, 0.03],

+

\step, [0.7, 1.25, \lin, 0.01, 1.03]] ! 2, 

+

   

+

[\freq, [600, 700, 900, 1000].collect([400, 1200, \lin, 0.01, _]),

+

\freqFac, [0.25, 1.25, \lin, 0.01, 1],

+

\attTime, [0.02, 2, \lin, 0.01, 0.2],

+

\relTime, [0.02, 2, \lin, 0.01, 2],

+

\susTime, [0.1, 10, \lin, 0.01, 5],

+

\amp, [0.0, 0.1, \lin, 0.001, 0.03],

+

\preAmp, [5, 50, \lin, 0.01, 20]] ! 2,

+

   

+

p!2, \synth_2 ! 2, quant: 0.4

+

).gui(tryColumnNum: 2, allowSynthsBreak: false, allowEnvirBreak: false  

+

/*, colorDeviation: 0 */

+

/*, sliderPriority: \synth, playerPriority: \synth */

+

)

+

)

+


+


+

Example 3:   granular synthesis with Tasks

+


+


+

(

+

// Synth definition for single synthesized grains, waveform to be selected by type 

+


+

SynthDef(\synth_3, { arg out = 0, freqLo = 1000, freqHi = 10000, amp = 0.1, type = 0, pan;

+

var env = EnvGen.kr(Env.perc(0.001, 0.003, amp),doneAction:2), freq;

+

freq = Rand(freqLo, freqHi);

+

OffsetOut.ar(out, Pan2.ar(Select.ar(type, [FSinOsc.ar(freq), Saw.ar(freq), Pulse.ar(freq)]), pan) * env) 

+

}).add;

+


+

// Task function definition. Although Tasks can be passed directly to VarGui as stream arg, 

+

// Functions have the advantage that the generated Tasks (as EventStreamPlayers with given Pbinds) 

+

// will be played in different environments automatically.

+

 

+

f = {

+

loop {

+

s.sendBundle(0.2, ["/s_new","synth_3", -1,0,0, 

+

\out, 0, 

+

\type, ~type, 

+

\amp, ~amp,

+

\freqLo, ~freqMid / ~freqIntvl.sqrt,

+

\freqHi, ~freqMid * ~freqIntvl.sqrt,

+

\pan, [1, -1].choose * ~pan]

+

);  

+

[~durShort, ~durLong].choose.wait;

+

}

+

};

+

)

+


+


+

(

+

v = VarGui( 3.collect { |i| [\type, [0, 2, \lin, 1, i],

+

\freqMid, [100, 8000, \lin, 1, 500 + (2000 * i)],

+

\freqIntvl, [1, 2.0, \lin, 0.01, 1.4],

+

\amp, [0.0, 0.2, \lin, 0.01, 0.05 * (i + 1)],

+

\pan, [0.0, 1.0, \lin, 0.01, 0.8],

+

\durShort, [0.005, 0.01, \lin, 0.001, 0.01],

+

\durLong, [0.01, 0.05, \lin, 0.001, 0.02]

+

] },

+

//  f!3 doesn't collect Functions as there is already a short notation for collecting Function values of Integers, e.g. (_*3)!5

+

stream: 3.collect { f }

+

).gui(colorDeviation: 0);

+

)

+


+


+


+

Example 4a:   interaction of synth and stream players, control synth controlling pbind synths

+


+


+

// Pbind producing a sequence of short events, each pbind-driven synth reading frequency from a control bus

+


+

( 

+

// control synth

+


+

SynthDef(\synth_4_kr, {|out = 0, devFreq = 0.5, midiCenter = 60, midiDev = 10|

+

Out.kr(out, LFDNoise3.kr(devFreq, midiDev, midiCenter))

+

}).add;

+


+

// audio synth

+

// mix of sine and pulse, interval, basic frequency read from control bus

+


+

SynthDef(\synth_4_ar, {|out = 0, in = 0, soundMix = 0.5, pulseWidth = 0.5, indexLR = 0,

+

att = 0.005, rel = 0.1, amp = 0.1, midiInt = 3, midiAdd = 0|

+

var mix, freq1, freq2, fr;

+

freq1 = (In.kr(in, 1) + midiAdd).midicps;

+

freq2 = freq1 * midiInt.midicps / 0.midicps;

+

fr = [Select.kr(indexLR, [freq1, freq2]), Select.kr(1-indexLR, [freq1, freq2])];

+

mix = (SinOsc.ar(fr, 0, amp) * (1 - soundMix)) + (Pulse.ar(fr, pulseWidth, amp) * soundMix);

+

Out.ar(out, EnvGen.ar(Env.perc(att, rel), doneAction: 2) * mix)

+

}).add;

+


+


+

x = Pbind(\instrument, \synth_4_ar,

+

\dur, 0.1,

+

\in, PL(\in),

+

\amp, PL(\amp),

+

\midiInt, Pfunc { rrand(~int[0], ~int[1]) }, // interval bounds

+

\rel, Pfunc { ~rel.choose }, // short and long release time

+

\soundMix, Pwhite(0.1, 0.9),

+

\indexLR, PLrand([0, 1])

+

);

+

)

+


+


+

(

+

// in GUI start control synth before EventStreamPlayer

+

// then try playing with sliders and pausing / resuming the control synth

+


+

c = Bus.control(s,1).index;

+


+

VarGui([\in, [c, c, \lin, 1, c], // bus fixed, display only

+

\int, [3,4].collect([0, 19, \lin, 0.1, _]), 

+

\rel, [0.01, 0.15].collect([0.01, 0.4, \lin, 0.005, _]), 

+

\amp, [0.0, 0.3, \lin, 0.01, 0.15]],

+

+

[\midiCenter, [45, 80, \lin, 0.1, 70],

+

\midiDev, [0, 20, \lin, 0.1, 20], 

+

\devFreq, [0.1, 15, \lin, 0.1, 1],

+

\out, c], // bus fixed, display only

+

x, \synth_4_kr

+

).gui(sliderPriority: \synth, playerPriority: \synth)

+

)

+


+


+


+

Example 4b:   interaction of synth and stream players, pbind and control synth controlling audio synth

+


+


+

// audio synth controlled by LFO pitch synth and a Pbind setting synth args (like Pmono)

+

// PLx ListPatterns taken here as they default to repeats = inf

+


+

(

+

y = Pbind(\type, \set,

+

// sequencing of durations and amplitudes quite fixed, just global tempo and amp control

+

\dur, PLshufn([0.15, 0.15, 0.35]) / PL(\tempo),

+

\amp, PLrand([0.05, 0.12, 0.2]) * PL(\amp),

+

\soundMix, PLseq([0.1, 0.5, 0.9]),

+

\indexLR, PLrand([0, 1]),

+

+

\midiInt, Pfunc { rrand(0, ~intMax) },

+

\args, [\amp, \soundMix, \midiInt, \indexLR] // args to be set must be listed

+

);

+


+


+

// In GUI start control synth (#0) first, then audio synth (#1) and EventStreamPlayer,

+

// then try playing with sliders and pausing / resuming the control synth and EventStreamPlayer.

+


+


+

d = Bus.control(s,1).index;

+


+

VarGui([ \tempo, [0.7, 1.2, \lin, 0.01, 1], 

+

\amp, [0.0, 1.5, \lin, 0.01, 0.7], 

+

\intMax, [-12, 12.0, \lin, 0.1, 8]],

+


+

[[\midiCenter, [45, 80, \lin, 0.1, 60],

+

\midiDev, [0, 20, \lin, 0.1, 1.5], 

+

\devFreq, [0.1, 15, \lin, 0.1, 10],

+

\out, d], // just display bus indices

+

[\in, d,

+

\out, 0,

+

\rel, 10000]], // ignore Env.perc definition

+


+

y, [\synth_4_kr,\synth_4_ar] 

+

).gui(sliderPriority: \synth, playerPriority: \synth)

+

)

+


+


+


+

Example 5a:   reordering of var control

+


+


+

// One may want to have controls grouped per name, not per Environment (resp. Pbind, Task, Synth),

+

// this can be achieved by passing a flat (not grouped) array of specPairs and the appropriate grouping,

+

// there are methods implemented for that special case of reordering:

+


+

(

+

// SynthDef from (1a)

+


+

p = Pbind(

+

\instrument, \synth_1a,

+

\preAmp, PL(\preAmp),

+

\amp, PL(\amp),

+

\midinote, Pfunc { ~midi + rrand(~midiDev.neg, ~midiDev) }, 

+

\dur, 0.2

+

);

+


+

// flat specPairs array without multiple keys

+


+

~specPairs = [\midi, [24, 80, \lin, 1, 36],

+

\midiDev, [0, 0.5, \lin, 0.01, 0.25],

+

\amp, [0, 0.3, \lin, 0.01, 0.1],

+

\preAmp, [5, 50, \lin, 0.01, 25]];

+


+

// get flat expansion of specPairs and appropriate groups

+

+

~specPairsDupped = ~specPairs.specPairsDup(5).postln;

+

~specPairsGroups = ~specPairs.specPairsDupGroups(5);

+

)

+


+


+

// parallel slider movement with Alt (not an array here but identically named variables in different envirs)

+

// parallel player action with Shift-click

+


+

(

+

v = VarGui(

+

~specPairsDupped, 

+

stream: p!5, 

+

varEnvirGroups: ~specPairsGroups, 

+

quant: 0.2

+

).gui(colorDeviation: 0);

+

)

+


+

// compare implicit mapping by passing a grouped collection of specPairs as varCtr arg

+


+

(

+

v = VarGui(

+

~specPairs!5, 

+

stream: p!5, 

+

quant: 0.2

+

).gui(colorDeviation: 0);

+

)

+


+

// Note that in the case of not connected varEnvirGroups the column break gui option

+

// allowEnvirBreak is ignored, means always set to true.

+


+


+


+

Example 5b:   reordering of synth control

+


+


+

(

+

SynthDef(\synth_5b, { |devFactor = 0.1, devFreq = 10, amp = 0.1|

+

var freq = XLine.kr(2000, 400, 3); 

+

Out.ar(0, Pan2.ar(SinOsc.ar(SinOsc.ar(devFreq, 0, devFactor * freq, freq), mul: amp), LFDNoise3.ar(2)) * EnvGate.new) 

+

}).add;

+


+


+

~specPairs = [\devFactor, [0, 0.99, \lin, 0.01, 0.5], 

+

\devFreq, [1, 100, \lin, 0.1, 70],

+

\amp, [0, 0.02, \lin, 0.001, 0.01]];

+


+

~num = 10; // ~num = 20;  use gui args sliderHeight and tryColumnNum for larger nums

+


+

v = VarGui(

+

synthCtr: ~specPairs.specPairsDup(~num), 

+

synth: \synth_5b ! ~num,

+

synthCtrGroups: ~specPairs.specPairsDupGroups(~num)

+

).gui(colorDeviation: 0 /* ,sliderHeight: 12, tryColumnNum: 2 */);

+

)

+


+

// compare implicit mapping by passing a grouped collection of specPairs as synthCtr arg

+


+

(

+

~num = 10;

+


+

v = VarGui(

+

synthCtr: ~specPairs ! ~num, 

+

synth: \synth_5b ! ~num

+

).gui(colorDeviation: 0);

+

)

+


+

// Note that in the case of not connected synthCtrGroups the column break gui option

+

// allowSynthBreak is ignored, means always set to true.

+


+


+


+

Example 6a:   non standard usage: passing Synths 

+


+


+

// Passing symbols or strings as synth args, refering to known (added) SynthDefs, is recommended

+

// However also Synths or nodeIDs can be given, but the player would have to know their state,

+

// so Synths should be registered

+


+

(

+

SynthDef(\sine, { |freq = 400, amp = 0.1| Out.ar(0, SinOsc.ar(freq, mul: amp)) }).add;

+

SynthDef(\pulse, { |freq = 400, amp = 0.1| Out.ar(0, Pulse.ar(freq, mul: amp)) }).add;

+

)

+


+

(

+

x = Synth(\sine).register;

+

y = Synth(\pulse).register;

+

)

+


+

// pause pulse 

+


+

y.run(false);

+


+

// VarGui checks state, definition is known, new Synths of same definition can be started

+


+

v = VarGui(synth: [x,y]).gui;

+


+


+

// With nodeIDs or non-registered Synths VarGui demands addtional state info

+


+

(

+

x = { SinOsc.ar(400, mul: 0.1) }.play;

+

y = { Pulse.ar(700, mul: 0.01) }.play;

+

)

+


+

y.run(false);

+


+

// no new Synths from temporary synth definition

+


+

v = VarGui(synth: [x,y], assumePlaying: true, assumeRunning: [true, false]).gui;

+


+


+


+

Example 6b:   non standard usage: setting sliders from outside

+


+


+

/// Synth definition with arrayed control

+

+

(

+

SynthDef(\vibes, { |amp = 0.005, devFactor = 0.1, devFreq = 10, devDisturb = 0.1| 

+

var freq = \midi.kr(20!30).midicps;

+

Out.ar(0, Mix.fill(30, {|i| [i.even.if {0}{1}, i.even.if {1}{0}] * 

+

SinOsc.ar(SinOsc.ar(devFreq * LFDNoise3.ar(0.5, devDisturb), 

+

0, devFactor * freq[i], freq[i]), mul: amp) } )) 

+

}).add;

+

)

+

+


+

// open gui with random midi values first, start playing 

+


+

(

+

v = VarGui( 

+

synthCtr: [\devFactor, [0, 0.01, \lin, 0.001, 0.005],

+

\devFreq, [0, 1, \lin, 0.01, 0.5], 

+

\devDisturb, [0, 0.99, \lin, 0.01, 0.1], 

+

\amp, [0, 0.05, \lin, 0.001, 0.005],

+

\midi, 30.collect { [45.0, 95, \lin, 0.01, rrand(45,95)] }

+

], 

+

synth: \vibes

+

).gui;

+

)

+


+


+

// update whole control array with one random value

+

// second arg synth index

+


+

v.updateSynthSliders(\midi, 0, rrand(50, 80.0)!30);

+


+


+

// update random group, fourth arg start index

+

// evaluate several times

+


+

v.updateSynthSliders(\midi, 0, rrand(50, 80.0)!5, rrand(0,25));

+


+

+

// phase shift gui

+


+

(

+

p = Pbind(

+

\dur, 0.07,

+

\type, \rest,

+

\i, Pseries(),

+

\do, Pfunc { |e| v.updateSynthSliders(\midi, 0, (e.i / 5).sin * 25 + 70, e.i % 30) }

+

).play(AppClock)

+

)

+


+


+

// stop updating

+


+

p.stop;

+


+


+


+

Example 6c:   non standard usage: setting values for plotting

+


+


+

// By setting a slider hook arbitrary actions can be triggered with lifting a slider handle.

+

// A slider hook can e.g. trigger the refreshing of a plot of parametric functions.

+


+

(

+

p = Plotter("move slider to plot", bounds: Rect(200, 200, 700, 500));

+


+

// number of plots in window

+


+

n = 5; 

+


+

// VarGui with random init params

+


+

v = VarGui({ [

+

\a, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2,

+

\b, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2] } ! n,

+

envir: () ! n

+

).gui;

+


+

// definition of parametric function, environment of variables will be defined later on

+


+

f = { |x| (x * ~a[0]).sin * ~b[0] + ((x * ~a[1]).sin * ~b[1]) }; 

+


+

// evaluation points

+


+

x = (0, 0.1..20);

+


+

// add slider hook, index not defined, everything will be refreshed with arbitrary sliderView mouseUp

+


+

v.addSliderAction { p.value_(v.envirs.collect { |e| f.inEnvir(e).(x) }).refresh };

+


+

// slider movements affecting more than one plot can be achieved with modifier combinations including alt

+

)

+


+


+


+

Example 7:   color grouping

+


+


+

// By default color grouping is based on logical separations:

+

// different synths and environments, different variables and controls, arrays.

+


+

// But apart of that there might exist more related controls

+

// and you'd like to overrule default color grouping.

+

// Especially with a large number of sliders a useful color grouping makes

+

// control much more convenient (also see examples in Buffer Granulation). 

+


+


+

// SynthDef where freq and amp controls could be grouped

+


+

(

+

SynthDef(\synth_7, { |freq = 400, freqOsc = 10, freqDev = 0.03, preAmp = 5, amp = 0.1|

+

var src = SinOsc.ar(SinOsc.ar(freqOsc, 0, freqDev * freq, freq), 0, mul: preAmp).tanh ! 2;

+

Out.ar(0, src * amp * EnvGate())

+

}).add;

+

)

+


+


+


+

// The clumps method is fine for grouping

+


+

(

+

~g = (0..4).clumps([3,2]);

+


+

~synthCtr = [

+

\freq, [20, 5000, \exp, 0, 80],

+

\freqOsc, [0, 20.0, \lin, 0, 10],

+

\freqDev, [0, 0.5, \lin, 0, 0.03],

+

\preAmp, [5, 50, \lin, 0.01, 20],

+

\amp, [0, 0.2, \lin, 0.01, 0.03]

+

];

+

)

+


+


+

// GUI with one Synth

+


+

VarGui(synth: \synth_7, synthCtr: ~synthCtr).gui(synthColorGroups: ~g);

+


+


+

// GUI with two Synths and separate colors for the second

+


+

VarGui(synth: \synth_7!2, synthCtr: ~synthCtr!2).gui(synthColorGroups: ~g+5 ++ ~g);

+


+


+

// Duplicating colors

+


+

(

+

~h = [~g, ~g+5].flop.collect(_.flat);  // or ~h = ~g.collect { |x| x + 5 ++ x };

+


+

VarGui(synth: \synth_7!2, synthCtr: ~synthCtr!2).gui(synthColorGroups: ~h);

+

)

+


+


+


+


+

Example 8:   EZSmoothSlider, EZRoundSlider

+


+


+

// EZSlider is used as default slider type.

+

// With wslib installed (Quark) you can choose 

+

// its slider types EZSmoothSlider and EZRoundSlider 

+

// as gui option 

+


+


+

VarGui(synth: \default).gui(sliderType: \smooth);

+


+

VarGui(synth: \default).gui(sliderType: \round);

+


+


+

// you can choose from their modes \jump (\default) or \move as general option

+


+

VarGui(synth: \default).gui(sliderType: \smooth, sliderMode: \move);

+


+


+

// if you want to set individually you can refer to sliders directly

+

// compare different slider behaviour of Synth 0 and 1

+


+

(

+

v = VarGui(synth: \default!2).gui(sliderType: \smooth, sliderMode: \move);

+


+

v.synthCtrSliders.first.sliderView.mode_(\jump)

+

)

+


+

// For multiple slider handling see Ex 1c.

+


+

// Very small numbers are forced to exponential notation (see also Ex. 9).

+


+

+


+

Example 9:   slider step precision

+


+


+

// VarGui makes some adaptions concerning slider step sizes and rounding

+

// depending on passed controlspec step size

+

// in order to unify slightly different behaviour of GUI kits

+

// and set parameters automatically also for very small step sizes.

+


+

// For this reason (and because of multiple slider handling) 

+

// scaling by modifiers is disabled by default.

+

// You can have a finer control by moving the mouse over the NumberBox,

+

// this also works with modifiers for multiple sliders (Ex.1c, Ex.2).

+


+


+

VarGui([\a, [0, 1, \lin, 0.1, 0]]).gui;

+


+

VarGui([\a, [0, 1, \lin, 0.01, 0]]).gui;

+


+

VarGui([\a, [0, 1, \lin, 0.001, 0]]).gui;

+


+


+


+

VarGui([\a, [0, 100, \lin, 1, 0]]).gui;

+


+

VarGui([\a, [0, 10000, \lin, 10, 0]]).gui;

+


+

VarGui([\a, [0, 10000, \lin, 100, 0]]).gui;

+


+


+

// controlspec step = 0 causes division of range by 100

+


+

VarGui([\a, [0, 1, \lin, 0, 0]]).gui;

+


+

VarGui([\a, [0, 0.1, \lin, 0, 0]]).gui;

+


+

VarGui([\a, [0, 1000, \lin, 0, 0]]).gui;

+


+


+

// division parameter can be changed

+


+

VarGui([\a, [0, 1000, \lin, 0, 0]]).gui(stepEqualZeroDiv: 10);

+


+

VarGui([\a, [0, 0.1, \lin, 0, 0]]).gui(stepEqualZeroDiv: 10);

+


+


+


+

// in case of very long numbers it may be necessary to adapt numberWidth

+


+

VarGui([\a, [0, 0.001, \lin, 0, 0]]).gui(numberWidth: 70);

+


+


+

// In general ranges are adapted to step size if necessary - 

+

// this is ControlSpec's standard behaviour

+


+

VarGui([\a, [1000, 5000, \lin, 1000.001, 0]]).gui(numberWidth: 70);

+


+


+

// a rather exotic option: 

+

// precisionSpan defaults to 10 and fails here ...

+


+

VarGui([\a, [10000000, 50000000, \lin, 10000000.001, 0]]).gui(numberWidth: 100);

+


+


+

// ... but resolves this

+


+

VarGui([\a, [10000000, 50000000, \lin, 10000000.001, 0]]).gui(precisionSpan: 12, numberWidth: 100);

+


+


+


+

Example 10:   MIDI learn functionality with sliders

+


+


+

// Connect your midi device, maybe you have to restart SC then.

+

// As gui example e.g. take SynthDefs and Pbind x from (4a), evaluate both code blocks.

+

// It must be possible to refer to the VarGui instance (e.g. v = VarGui(...))

+


+

// start MIDI

+


+

MIDIIn.connectAll

+


+

// on your device define desired knobs, faders etc. to send cc messages

+

// probably you want to control different parameters, so define different cc numbers

+

 

+

// start learning mode

+


+

v.startMIDIlearn

+


+


+

// now assignment can happen by selecting a VarGui slider box

+

// it gets a focus (blue border, sometimes not very well visible)

+

// then send midi cc with the fader/knob of your choice

+

// sending data with different cc number, while the same slider is still or again selected, will overwrite

+


+

// end of learning has to be defined

+


+

v.stopMIDIlearn

+


+


+

// adaption of control can be done by recalling the learning mode

+


+

v.startMIDIlearn

+


+

...

+


+

v.stopMIDIlearn

+


+


+ + diff --git a/Help/Working with HS and HSpar.html b/Help/Working with HS and HSpar.html new file mode 100644 index 0000000..c091dbb --- /dev/null +++ b/Help/Working with HS and HSpar.html @@ -0,0 +1,147 @@ + + + + + + + + + + + +

Working with HS and HSpar objects for use of synth values in the language by event patterns

+


+

Part of: miSCellaneous

+


+

See also: HS, PHS, PHSuse, HSpar, PHSpar, PHSparUse, PHSplayer, PHSparPlayer, PHSusePlayer, Event patterns and LFOs, HS with VarGui

+


+


+

Motivation

+


+

Sometimes it may be desirable to use synth values in a Pbind (actually the derived EventStreamPlayer), I'm especially thinking of LFO-like controls for the generated synth(s). There are different ways to do this or something similar, see Event patterns and LFOs for examples.

+


+

As a general distinction for an event stream you can have new control values per event (1) or continuous control (2).

+

Some possible implementations:

+


+

attachments/Working with HS and HSpar/tab_2b.png

+


+

There also exist elaborated language solutions that can be used in the above sense: see the interpolation methods in Wouter Snoei's wslib quark and (based on that) Splines with gui by crucialfelix.

+


+

For (1) and (2) LFO behaviour can be defined using help synths (1c, 1d, 1e, 2a, 2b). If the Pbind-generated synths read values from control buses (1e, 2a, 2b), you don't have these values in the language (well, maybe you don't need them). With (1c) you have to use the internal server (of course this may also be ok).

+

Having to define audio SynthDefs with respect to possible future control needs (1e, 2a) though is a bit unflexible. So (1d) integrates some nice features, nevertheless this has to be traded off with additional latency inherent in its mechanism: by using HS / PHS (and relates) help synth values are sent back to the client via OSCresponders, which works with local and internal server.

+

The HS / PHS approach would especially be of interest if control behaviour could more easily be defined by server means than in SC lang (e.g. specific and / or nested UGens) but data should also be further manipulated in the language (e.g. for some kind of combinatorial use such as harmonic or polyphonic calculations). As a separate feature HSpar / PHSpar support timed and combinatorial possibilities to refer to more than one control synth (e.g. switching). This type of control, however, would not necessarily have to use the underlying demand-respond implementation.

+


+


+

Working scheme

+


+

1.) Define help synth(s) by HS or HSpar.

+

+

These objects hold synth definitions, HS holds a single synth definition,

+

HSpar can hold more than one and has additional features.

+


+

2.) Define Pbind(s) by PHS (for HS) or PHSpar (for HSpar) to use synth values.

+


+

3.) Play PHS / PHSpar.

+


+

This instantiates a PHSplayer / PHSparPlayer object. Synth values are demanded and received for the use in defined Pbinds, HS / HSpar keep track of OSC traffic. PHSplayer / PHSparPlayer can be stopped and started with options, concerning Pbinds and help synths.

+


+

Option, may be done immediately with (2) and (3) or later to "step in":

+


+

4.) Define further Pbind(s) by PHSuse / PHSparUse which refer to the same HS / HSpar.

+


+

5.) Play PHSuse / PHSparUse.

+


+

A PHSusePlayer object is instantiated, which can also be stopped and started with options. Different from PHSplayer / PHSparPlayer these options are not affecting help synth control, which is defined by PHS / PHSpar or can be done by their players' methods stop and play. Therefore steps (4) and (5) require the preceding definition resp. playing of PHS / PHSpar. Synchronization with other players can be done by the use of Quant objects. 

+

Instead of using PHSuse / PHSparUse objects in order to have separate players it's also possible to define several HS / HSpar objects independently. See PHSparUse for an example.

+

A VarGui interface may be generated before step (3), see HS with VarGui. 

+


+


+

Latency

+


+

Due to the mechanism of demanding and receiving a synth value before sending an actual message defined by the event pattern, there is a latency in addition to and independent from normal server latency (actually there are two, called demandLatency and respondLatency). demandLatency is the latency of the help synth(s) in relation to the synth value demands, driven by the Pbind duration pattern, respondLatency means the time given to the response to be received safely on time by the client.

+

If these additional latencies are too small the communication between client and server may loose track of synth values needed by the event pattern and the mechanism breaks. On the other hand large latencies and heavy OSC traffic could need more CPU for bookkeeping - maybe you have to play around to find right values. Using the default latencies of HS / HSpar (demandLatency = 0.15, respondLatency = 0.15) and the Server (latency = 0.2) there is an overall latency of 0.5 sec (and in most cases you could lower this a lot if you need to). I didn't intend to use the whole thing for live performance, so just be aware.

+


+


+

OSC demand / respond mechanism to use server values in event streams

+


+

Suppose HS defined, this happens when PHS is played:

+


+


+

1.) latency = 0

+

     sequence of duration values generated in language

+


+

attachments/Working with HS and HSpar/latency_1.png

+


+


+

2.) latency = demandLatency 

+

(timing accuracy depends on defined time granulation) 

+

in server: synth started, values taken at scheduled times

+

+

attachments/Working with HS and HSpar/latency_2.png

+

+

3.) latency = demandLatency + respondLatency

+

back in language, synth values can be used 

+

e.g. to generate control data for an instrument

+

+

attachments/Working with HS and HSpar/latency_3.png

+


+

4.) latency = demandLatency + respondLatency + server latency

+

if note event: (audio) synth started

+

+

attachments/Working with HS and HSpar/latency_4.png

+


+


+

Relation to Pbinds and EventStreamPlayers

+


+

PHS / PHSpar are almost "like" Pbind objects in the way, that event stream behaviour is defined. Internally two event patterns are defined, one for demand time and one for receive time. Consequently PHSplayer / PHSparPlayer also consist of more than one EventStreamPlayer (PHSparPlayer contains a third one for switching between help synths). This splitting seemed necessary for stopping and resuming Pbind(s) and help synth(s).

+

You can easily sync PHSplayers / PHSparPlayers / PHSusePlayers themselves or with other EventStreamPlayers via Quant objects. The corresponding play methods take into account the needed time (caused by latency) to step into the quantization as early as possible.

+


+


+

Granularity - internal quantization

+


+

If several Pbinds are played in parallel, demands for values of the same help synth can be very close together, which causes possibly unnecessary OSC traffic: If accuracy of synth values is not very important (and for LFO-like purposes it is probably not) it seems sufficient to identify synth values from a small time region. This is done by the HS / HSpar parameter granularity, which defaults to 200, defining a time region of 0.005 seconds. Synth value demands within such a region are using just one (namely the first) demanded value, scheduling itself isn't affected. Mostly you won't have to think about this quantization - note that it has nothing to do with Quant objects and synchronizing players.

+


+


+

Synth value access

+


+

In the case of a single help synth (HS), values are accessible within the PHS / PHSuse by the local variable ~val, e.g. by Pkey(\val) or a construction with Pfunc. In the case of several help synths (HSpar), there is the option of defining a separately timed pattern to switch between playing help synths, always marking one as "current". Then ~val refers to this current help synth, but reference behaviour can be differentiated by options and other keywords within the PHSpar / PHSparUse to get values of all playing help synths and other values (indices) which may be useful for control definitions. See examples in the help file PHSpar, e.g. the last one.

+


+


+

Order of execution

+


+

If more than one Pbind is defined via PHS / PHSuse / PHSpar / PHSparUse the corresponding players will be started in order of definition with a small amount of time-shift between them, so that they can refer to each other (especially at coinciding points of logical time). See the last example of PHS.

+


+


+

About the examples

+


+

Examples in the doc files use help synths values mainly for pitch - this seemes to make the concept quite clear. I preferred to take the default instrument to emphasize what is happening structurally. See HS examples for other usages. 

+

Be sure to have the right HS / HSpar definition evaluated before defining resp. playing a PHS / PHSpar ! - examples usually begin with a HS / HSpar definition and are thought to be worked through following the comments.

+


+


+ + diff --git a/Help/ZeroXBufRd.html b/Help/ZeroXBufRd.html new file mode 100755 index 0000000..dee04b6 --- /dev/null +++ b/Help/ZeroXBufRd.html @@ -0,0 +1,889 @@ + + + + + + + + + + + +

ZeroXBufRd reads consecutive sequences of segments between zero crossings from one or more buffers with demand-rate control

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

ZeroXBufRd is for consecutive reading of segments between zero crossings (half wavesets) from one or more buffers, whereby several reading and processing parameters can be sequenced with demand rate ugens. Full waveset sequences can so be generated as a special case. It needs analysis data prepared with ZeroXBufWr. For triggering possibly overlapped (half) wavesets see TZeroXBufRd. ZeroXBufRd / TZeroXBufRd can be used for a number of synthesis / processing techniques in a field between wavesets [1, 4, 5], pulsar synthesis [1, 3], buffer modulation and rectification (which are both a kind of waveshaping) and stochastic concatenation methods [2, 6]. There are already existing SC waveset implementations like Alberto de Campo's Wavesets quark (https://github.com/supercollider-quarks/quarks) and Olaf Hochherz's SPList (https://github.com/olafklingt/SPList), which do language-side analysis and Fabian Seidl's RTWaveSets plugin (https://github.com/tai-studio/RTWaveSets). My focus has been server-side analysis and demand rate ugen control of half waveset parameters as well as multichannel and buffer switch options. Realtime control while analysis is possible, as long as reading is only refering to already analysed sections, but clearly most flexibility is given with a fully analysed buffer, which can also be done in quasi realtime.

+


+

NOTE: Depending on the multichannel sizes and the options used (rate and dir sequencing) it might be necessary to increase server resources, i.e. the number of interconnect buffers and / or memory size (e.g. s.options.numWireBufs = 256; s.options.memSize = 8192 * 32; s.reboot). Because of overlappings this is more relevant with TZeroXBufRd than with ZeroXBufRd.

+


+

NOTE: Often it pays to adjust zero crossings in the sound buffer effectively to 0, that way sawtooth-like interpolation artefacts can be avoided. See Ex. 7 below.

+


+

NOTE: The reading of consecutive half wavesets is implemented with Sweep and retriggering. For that reason each played back half waveset has a minimum length of 2 samples. In the case of adjusted zero crossings that immediately follow each other this can lead to flat sections of a few samples length. Normally this is irrelevant, but you might check setting ZeroXBufWr's adjustZeroXs flag to 2, see the example there and below.

+


+

NOTE: Demand rate UGens in ZeroXBufRd / TZeroXBufRd must always use inf as repeats arg, this is of course not necessary for nested ones. You might pass a length arg though (Ex. 5).

+


+

NOTE: For avoiding too long half wavesets it might be useful to apply LeakDC resp. a high pass filter before analysis.

+


+

NOTE: In rare cases I noticed corrupted buffers in multi buffer examples for no obvious reason.

+


+

NOTE: For full functionality at least SC 3.7 is recommended (rate sequencing doesn't work in 3.6)

+


+


+

CREDITS: Thanks to Tommaso Settimi for an inspiring discussion, which gave me a nudge to tackle these classes. 

+


+


+

REFERENCES:

+


+

[1] de Campo, Alberto. "Microsound" In: Wilson, S., Cottle, D. and Collins, N. (eds). 2011. 

+

The SuperCollider Book. Cambridge, MA: MIT Press, 463-504.

+

+

[2] Luque, Sergio (2006). Stochastic Synthesis, Origins and Extensions. Institute of Sonology, Royal Conservatory, The Netherlands. 

+

http://sergioluque.com

+


+

[3] Roads, Curtis (2001). Microsound. Cambridge, MA: MIT Press.

+

+

[4] Seidl, Fabian (2016). Granularsynthese mit Wavesets für Live-Anwendungen. Master Thesis, TU Berlin.

+

https://www2.ak.tu-berlin.de/~akgroup/ak_pub/abschlussarbeiten/2016/Seidl_MasA.pdf

+


+

[5] Wishart, Trevor (1994). Audible Design. York: Orpheus The Pantomime Ltd. 

+


+

[6] Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition.

+


+


+


+

See also: TZeroXBufRd, ZeroXBufWr, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies

+


+


+

Creation / Class Methods

+


+

*ar (sndBuf, zeroXBuf, bufMix, zeroX = 0, power = 1, mul = 1, add = 0, rate = 1, rateMul = 1, dir = 1, interpl = 4, dUniqueBufSize = 1048576,

+

length = inf, maxTime = inf, att = 0, rel = 0, curve = -4, doneAction = 0)

+

+

sndBuf - Buffer or SequenceableCollection of Buffers to read the data from, data must correspond to zeroXBuf.

+

zeroXBuf - Analysis Buffer resp. SequenceableCollection of such, prepared with ZeroXBufWr. 

+

Must refer to data passed to sndBuf.

+

bufMix - A Number indicating the sndBuf index, a demand rate or other ugens returning sndBuf indices or 

+

a SequenceableCollection of such. In contrast to other args combinations of demand rate and normal ugens are not valid. 

+

If bufMix equals nil (default) the size of the returned signal equals the size of sndBuf,

+

otherwise it equals its own size.

+

zeroX - A Number indicating the index in zeroXBuf, a demand rate or other ugens returning zeroXBuf indices or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of zeroX

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 0.

+

power - Used for processing the buffer signal according to the formula: sig ** power * mul + add per half waveset. 

+

Must be a positive Number, a demand rate or other ugens returning power values or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of power

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1.

+

mul - Used for processing the buffer signal according to the formula: sig ** power * mul + add per half waveset. 

+

Must be a Number, a demand rate or other ugens returning mul values or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of mul

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 1. 

+

add - Used for processing the buffer signal according to the formula: sig ** power * mul + add per half waveset. 

+

Must be a Number, a demand rate or other ugens returning add values or 

+

a SequenceableCollection of such.

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of add

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

Defaults to 0. 

+

rate - Determines the playback rate per half waveset together with rateMul. 

+

Must be a positive Number, a demand rate or other ugens returning rate values or a SequenceableCollection of such. 

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of rate

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

In contrast to other args combinations of demand rate and normal ugens are not valid for implementational reasons. 

+

Though you can pass a demand rate ugen here and a normal ugen to rateMul (or vice versa) which are then multiplied per half waveset.

+

Defaults to 1.

+

rateMul - Determines the playback rate per half waveset together with rate. 

+

Must be a positive Number, a demand rate or other ugens returning rateMul values or a SequenceableCollection of such. 

+

If in this case the overall multichannel size determined by sndBuf or bufMix is larger than the size of rateMul

+

and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once.

+

In contrast to other args combinations of demand rate and normal ugens are not valid for implementational reasons. 

+

Though you can pass a normal ugen here and a demand rate ugen to rate (or vice versa) which are then multiplied per half waveset.

+

Defaults to 1.

+

dir - Determines the playback direction of half wavesets. 

+

Must be +1 or -1, a demand rate or other ugens returning dir values or 

+

a SequenceableCollection of such.  If in this case the overall multichannel size determined by sndBuf or bufMix is 

+

larger than the size of dir and the latter contains demand rate ugens, they must all be wrapped into Functions for 

+

being used more than once. In contrast to other args combinations of demand rate and normal ugens are not valid.

+

Defaults to 1. 

+

interpl - Determines the interpolation type for the BufRd ugens. 

+

Must equal 1 (no), 2 (linear) or 4 (cubic) or a SequenceableCollection of these numbers.

+

Defaults to 4. 

+

dUniqueBufSize - Determines the buffer size for Dunique objects which have to be used in the case

+

of demand rate ugens passed to rate, dir or bufMix. See Ex.2.

+

Must be an Integer or a SequenceableCollection of Integers.

+

Defaults to 1048576. 

+

length - Determines the number of triggers before release of the overall asr envelope. 

+

Can be a Sequenceable Collection too. Overruled by maxTime if this is reached before.

+

Defaults to inf. 

+

maxTime - Determines the time before release of the overall asr envelope. 

+

Can be a Sequenceable Collection too. Overruled by length if this is reached before.

+

Defaults to inf. 

+

att - Attack time of overall asr envelope or SequenceableCollection thereof. 

+

Defaults to 0. 

+

rel - Release time of overall asr envelope or SequenceableCollection thereof.  

+

Defaults to 0. 

+

curve - Curve of overall asr envelope or SequenceableCollection thereof.  

+

Defaults to -4. 

+

doneAction - Done action of overall asr envelope or SequenceableCollection thereof.  

+

Defaults to 0. 

+

+

+


+

Examples

+


+

(

+

// boot with extended resources, might be needed for some examples

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.options.memSize = 8192 * 32; 

+

s.reboot;

+

)

+


+


+

Ex.1) Basic usage

+

+

// prepare two short buffers for audio and zero crossing data

+

// the size of needed zeroX data space can be roughly estimated

+


+

(

+

b = Buffer.alloc(s, 2000);

+

z = Buffer.alloc(s, 200);

+

)

+


+

// analyse a short snippet of ring modulation

+


+

(

+

{

+

var src = SinOsc.ar(300) * SinOsc.ar(120) + SinOsc.ar(30) * 0.1;

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+


+

// check the waveform

+


+

b.plot

+


+


+


+

// loop 3rd half waveset

+

// compare plot and scope

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 2) }.play

+


+

s.scope

+


+

x.release

+


+


+

// loop a whole waveset

+

// demand rate ugens in ZeroXBufRd should always use inf as repeats arg

+

 

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf)) }.play

+


+

x.release

+


+


+

// Note that the distance between zero crossings can be very short,

+

// here the half waveset at index 5 (735-740) has a length of only 5 samples and the amplitude is low.

+


+

// zero crossing indices

+


+

z.loadToFloatArray(action: { |b| b.postln })

+


+


+

// the signal is hardly audible, but there as freqscope shows

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 5) }.play

+


+

s.freqscope

+


+

x.release

+


+


+


+

// loop a group of 3 wavesets

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq((1..6), inf)) }.play

+


+

x.release

+


+


+


+

// sequence multiplier for half wavesets

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), mul: Dseq([1, 0.2], inf)) }.play

+


+

x.release

+


+


+

// mul can be used for rectifying effects

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq((1..2), inf), mul: Dseq([0, 1, 1], inf)) }.play

+


+

x.release

+


+


+


+

// add an offset sequence, this results in a pulse-like effect

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), add: Dseq([-0.05, 0.05], inf)) * 0.5 }.play

+


+

x.release

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), add: Dseq([0.05, -0.05], inf)) * 0.5 }.play

+


+

x.release

+


+


+


+

// half wavesets can also get a power,

+

// per waveset the signal is calculated according to

+

// ((sig ** power) * mul) + add

+


+

// be careful with this arg moving away from 1 ! 

+

// high power values can result in loud signals if the source has values outside [-1, 1] and

+

// small power values can also become loud with source values near zero

+


+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), power: 0.7) }.play

+


+

x.release

+


+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), power: Dseq([0.8, 1.7, 1], inf)) }.play

+


+

x.release

+


+


+


+

Ex.2) The 'rate' and 'dir' args

+


+

// needs Buffers from Ex.1

+


+

s.scope

+


+


+

// playback rates can be defined generally ...

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), rate: 2.5) }.play

+


+

x.release

+


+


+

// ... or as sequence

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), rate: Dseq((1..3), inf)) }.play

+


+

x.release

+


+


+

// slightly different: here the whole waveset gets one rate

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), rate: Dstutter(2, Dseq((1..3), inf))) }.play

+


+

x.release

+


+


+


+

// with the dir argument set to -1 the half wave set is reversed

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 7) }.play

+


+

x.release

+


+


+

// compare scope, no audible difference here

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 7, dir: -1) }.play

+


+

x.release

+


+


+

// dir can also be sequenced

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 7, dir: Dseq([1, 1, -1], inf)) }.play

+


+

x.release

+


+


+

// When demand rate ugens are used for 'rate' or 'dir' args ZeroXBufRd employs Dunique objects.

+

// This means that Buffers have to be allocated for counting, and if the Buffer is full

+

// the synthesis fails. By default a value of 1048576 is defined for 'dUniqueBufSize'.

+

// This should be sufficient for at least some minutes auf audio in average use cases.

+


+

// However with very fast triggering you might want to pass a higher value.

+

// With multichannel applications it might be necessary then to run the server with higher memSize.

+


+


+

// With a deliberately bad (low) size, sequencing fails after a second

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 1, rate: Dseq([1, 2], inf), dUniqueBufSize: 1024) }.play

+


+

x.release

+


+

// From low values you can roughly estimate the needed dUniqueBufSize to safely run your application

+

// for a given time

+


+


+


+


+

Ex.3) Passing ordinary UGens as args

+


+


+

// needs Buffers from Ex.1

+


+

// values are sampled and hold for the duration of the segments

+


+

s.scope

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: SinOsc.ar(SinOsc.ar(0.1).range(0.2, 5)).range(1, 15)) }.play

+


+

x.release

+


+


+

// more fun with moving rates

+


+

(

+

x = { 

+

ZeroXBufRd.ar(

+

b, z, 

+

zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15),

+

rate: SinOsc.ar(SinOsc.ar(0.3).range(0.2, 5)).exprange(1, 5)

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// warp effect with accelerating rates

+


+

(

+

x = { 

+

ZeroXBufRd.ar(

+

b, z, 

+

zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15),

+

rate: Dseq((1..50) / 20 + 0.5, inf)

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// also combinations of demand rate and ordinary ugens are possible

+

// though with the exception of rate, dir and bufMix args

+


+

(

+

x = { 

+

ZeroXBufRd.ar(

+

b, z, 

+

zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15),

+

rate: Dstutter(Dwhite(10, 100), Dwhite(0.5, 2)),

+

mul: Dseq([0.2, 0.2, 1], inf) * LFDNoise3.ar(5).range(1, 5)

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// for combinations of normal and demand ugens with the rate arg rateMul can be used

+


+

(

+

x = { 

+

ZeroXBufRd.ar(

+

b, z, 

+

zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15),

+

rate: Dstutter(Dstutter(3, Dwhite(1, 5)), Dseq([0.5, 1, 1.5], inf)),

+

rateMul: LFDNoise3.ar(5).range(1, 5)

+

) ! 2

+

}.play

+

)

+


+

x.release

+


+


+

// free resources

+


+

(

+

b.free;

+

z.free;

+

)

+


+


+

Ex.4) Multichannel usage and the 'bufMix' arg

+


+

// Without passing a bufMix arg the size of the returned signal is determined by the buffer input. 

+

// It may be a single channel buffer or an array of single channel buffers, 

+

// in correspondence with the analysis buffer(s) - multichannel buffers are not allowed. 

+

// If bufMix is passed, it determines the size of the returned signal, 

+

// its components can be demand rate or other ugens to control switching between buffers per half waveset.

+


+

// Note: buffer switching can become CPU-demanding with a lot of Buffers 

+

// as for fast switching it is necessary to play all in parallel

+


+

(

+

// boot with extended resources

+

s = Server.local;

+

Server.default = s;

+

s.options.numWireBufs = 256; 

+

s.options.memSize = 8192 * 32; 

+

s.reboot;

+

)

+


+


+

// prepare 3 buffers

+


+

(

+

b = { Buffer.alloc(s, 1000, 1) } ! 3;

+

z = { Buffer.alloc(s, 100, 1) } ! 3;

+

)

+


+

// fill with basic waveforms

+

(

+

{

+

var src = [

+

SinOsc.ar(400),

+

LFTri.ar(400),

+

SinOsc.ar(400) ** 10

+

];

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+


+

s.scope(3)

+


+

// play 3 channels

+


+

x = { ZeroXBufRd.ar(b, z, zeroX: 1) * 0.1 }.play

+


+

x.release

+


+


+

// play from 1st buffer

+


+

x = { ZeroXBufRd.ar(b, z, bufMix: 0, zeroX: Dseq([0, 1], inf)) * 0.2 }.play

+


+

x.release

+


+


+


+

// play from 3rd and 1st buffer

+

// to use equally defined demand rate ugens for both, wrap them into a Function

+


+

x = { ZeroXBufRd.ar(b, z, bufMix: [2, 0], zeroX: { Dseq([0, 1], inf) }) * 0.1 }.play

+


+

x.release

+


+


+

// play 2 channels with different zeroX sequences

+


+

(

+

x = {

+

ZeroXBufRd.ar(

+

b, z,

+

bufMix: [1, 2],

+

zeroX: [Dseq([0, 0, 1], inf), Dseq([0, 1], inf)]

+

) * 0.1

+

}.play

+

)

+


+

x.release

+


+


+


+


+

// buffers can be switched per half waveset

+


+


+

x = { ZeroXBufRd.ar(b, z, bufMix: Dseq([0, 1, 2], inf), zeroX: 2, mul: 0.3) }.play

+


+

x.release

+


+


+

x = { ZeroXBufRd.ar(b, z, bufMix: Dseq([0, 1], inf), zeroX: Dseq([1, 2], inf), mul: 0.3) }.play

+


+

x.release

+


+


+


+

// Gendy-like texture

+


+

(

+

x = {

+

ZeroXBufRd.ar(

+

b, z,

+

bufMix: { Dseq([0, 1, 2], inf) } ! 2,

+

zeroX: 2,

+

mul: 0.1,

+

// array of Drands with different offset

+

// the average of the Drand output is 50,

+

// so on average 1/4 is added to x

+

// and the harmonic relation of L:R is 5:7 -> tritone

+

rate: [1, 1.5].collect { |x| Drand((1..100) / 200 + x, inf) }

+

)

+

}.play

+

)

+


+

x.release

+


+


+

// bufMix determines size

+

// other args are expanded accordingly

+


+

(

+

x = {

+

ZeroXBufRd.ar(b, z,

+

bufMix: { Dseq([0, 1, 2], inf) } ! 2,

+

zeroX: { Dseq([1, 2], inf) },

+

mul: { Dstutter(Diwhite(1, 1000), Drand([0.01, 0.07, 0.2], inf)) },

+

rate: { Dstutter(Diwhite(1, 12), Dwhite(0.1, 10)) }

+

)

+

}.play

+

)

+


+

x.release

+


+


+


+

Ex.5) The overall envelope

+


+

// The finishing of a ZeroXBufRd is not detemined by finite demand rate ugens but by an overall envelope, 

+

// its release section is triggered by a maximum number of half wavesets ('length') or a maximum time. 

+


+

// Buffers from Ex.4

+


+

{ ZeroXBufRd.ar(b[0], z[0], rate: 1, length: 10, rel: 0.01) }.plot(0.03)

+


+

{ ZeroXBufRd.ar(b[0], z[0], rate: 1, maxTime: 0.01, rel: 0.01) }.plot(0.03)

+


+


+

// envelopes can be differentiated

+


+

{ ZeroXBufRd.ar(b[0..1], z[0..1], rate: 1, maxTime: [0.01, 0.005], rel: [0.005, 0.02]) }.plot(0.03)

+


+

{ ZeroXBufRd.ar(b[0..1], z[0..1], rate: 1, length: [7, 2], rel: [0.005, 0.02]) }.plot(0.03)

+


+


+

// there should be only one doneAction 2 in this case

+


+

{ ZeroXBufRd.ar(b[0..1], z[0..1], rate: 1, maxTime: [0.01, 0.005], rel: [0.05, 0.5], doneAction: [0, 2]) }.play

+


+


+

(

+

b.do(_.free);

+

z.do(_.free);

+

)

+


+


+

Ex.6) Simultaneous writing and reading

+


+


+

// The reading of half wavesets can start before analysis is finished,

+

// if ZeroXBufRd is carefully used in with a bit of delay.

+


+


+

// prepare buffers

+


+

(

+

p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";

+

b = Buffer.read(s, p);

+

)

+


+

(

+

z = Buffer.alloc(s, b.duration * 44100 / 5, 1);

+

s.scope;

+

)

+


+


+


+

// Here the average playback rate equals 1 (0.8 = 4/5, 1.25 = 5/4),

+

// so playback will not be faster than writing.

+


+

(

+

{

+

var src = PlayBuf.ar(1, b, BufRateScale.ir(b));

+

// write zero crossings, but no need to overwrite sound buffer

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, writeSndBuf: false);

+

DelayL.ar(

+

ZeroXBufRd.ar(

+

b, z,

+

// Dseries keeps counting through the half-filled zeroX buffer

+

zeroX: Dseries(),

+

rate: Dstutter(10, Dseq([0.8, 1, 1.25], inf)),

+

// estimate end time

+

maxTime: b.duration + 1,

+

doneAction: 2

+

),

+

0.2,

+

0.1

+

) ! 2;

+

}.play

+

)

+


+

(

+

b.free;

+

z.free;

+

)

+


+

// The same can be done with a live-generated signal or a mic input,

+

// but ensure that reading comes after writing !

+


+


+

// FAILURE BY BAD DEFINITION !

+

// rates are fast, so zeroX indices are referred before analysis 

+

// resulting in garbage noise

+


+


+

(

+

b = { Buffer.alloc(s, 5 * 44100) } ! 2;

+

z = { Buffer.alloc(s, 2 * 44100) } ! 2;

+

)

+


+


+

(

+

{

+

var src = LFDNoise3.ar(300 ! 2), sig;

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1);

+

sig = DelayL.ar(

+

ZeroXBufRd.ar(

+

b, z,

+

// Dseries keeps counting through the half-filled zeroX buffer

+

zeroX: { Dseries() },

+


+

rate: { Dseq((1..10) / LFDNoise3.ar(3).range(5, 10) + 1, inf) },

+

mul: { Dstutter(Dwhite(50, 500), Drand([0.02, 0.1, 0.5], inf)) },

+

// estimate end time

+

maxTime: 10,

+

att: 0.2,

+

rel: 5,

+

doneAction: 2

+

),

+

0.2,

+

0.1

+

);

+

LeakDC.ar(sig)

+

}.play

+

)

+


+


+


+

//  Reasonable realtime usage

+

//  zeroX is deferred by stuttering, rates are sufficiently low

+


+

(

+

b.do(_.zero);

+

z.do(_.zero);

+

)

+


+


+

(

+

{

+

var src = LFDNoise3.ar(3000 ! 2);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1);

+

DelayL.ar(

+

ZeroXBufRd.ar(

+

b, z,

+

zeroX: { Dstutter(Dwhite(50, 300), Dseries()) * 2 + Dseq((1..4), inf) },

+

rate: { Dseq((1..5) / LFDNoise3.ar(3).range(5, 10) + 0.5, inf) },

+

mul: { Dstutter(Dwhite(50, 500), Drand([0.05, 0.3, 0.7], inf)) },

+

// estimate end time

+

maxTime: 20,

+

att: 0.2,

+

rel: 5,

+

doneAction: 2

+

),

+

0.2,

+

0.1

+

);

+

}.play

+

)

+


+

(

+

b.do(_.free);

+

z.do(_.free);

+

)

+


+

// It's of course unproblematic – and still quasi realtime – to fully a analyse 

+

// a snippet of sound with ZeroXBufWr before freely using ZeroXBufRd in the same synth

+


+


+


+

Ex.7) Adjusting zero crossings

+


+


+

// In general a half waveset isn't totally unipolar:

+

// Zero crossing indices indicate the change of the sign of a signal,

+

// so with this convention the last sample of the half waveset itself

+

// has a different sign.

+


+

// This can have the consequence that, depending on the playback rate,

+

// sawtooth-like effects might occur. Such artefacts can be circumvented by

+

// adjusting buffer values at zero crossing indices to 0,

+

// so playback of (half) wavesets is smoothened, especially with extreme rate values.

+


+


+

(

+

p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";

+

b = Buffer.read(s, p);

+

z = Buffer.alloc(s, 100000);

+

)

+


+

// analyse buffer

+

(

+

{

+

var src = PlayBuf.ar(1, b, BufRateScale.ir(b), doneAction: 2);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, doneAction: 2);

+

}.play

+

)

+


+

// this half waveset clearly shows the effect

+

// (tested with samplerate 44100)

+


+

s.scope

+


+

x = { ZeroXBufRd.ar(b, z, nil, 220, rate: 0.1) * 2 }.play

+


+


+

// adjust zeros, also works with arrays of Buffers

+

// you can apply it while running, it might take a moment though

+


+

b.adjustZeroXs(z)

+


+

x.release

+


+


+

// alternatively adjusting zero crossings can be chosen as option with analysis:

+

// set flag 'adjustZeroXs' to 1

+


+


+

(

+

p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";

+

b = Buffer.read(s, p);

+

z = Buffer.alloc(s, 100000);

+

)

+


+

// analyse buffer

+


+

(

+

{

+

var src = PlayBuf.ar(1, b, BufRateScale.ir(b), doneAction: 2);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, adjustZeroXs: 1, doneAction: 2);

+

}.play

+

)

+


+

s.scope

+


+

x = { ZeroXBufRd.ar(b, z, nil, 220, rate: 0.1) * 2 }.play

+


+

x.release

+


+


+

// the flag 'adjustZeroXs' can also be set to 2

+

// in this case zero crossings have a minimum distance of 2 samples

+

// This goes along with ZeroXBufRd's convention to play one half waveset with a minimum length of 2 samples

+

// (otherwise it couldn't act as a trigger)

+


+

// the difference can be observed with fast switches between signs like with WhiteNoise

+


+

(

+

b = Buffer.alloc(s, 2000);

+

z = Buffer.alloc(s, 2000);

+

)

+


+

(

+

{

+

var src = WhiteNoise.ar();

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, adjustZeroXs: 1, doneAction: 2) * 0.2;

+

}.play

+

)

+


+

s.scope

+


+


+

// this generates a more pulsar-like waveform with adjacent zero crossings,

+

// note that transitions to flat sections are smoothened by cubic interpolation

+


+

x = { ZeroXBufRd.ar(b, z, nil, Dseq((0..50), inf), rate: 0.03) * 0.5 }.play

+


+

x.release

+


+


+

// there are no flat sections with 'adjustZeroXs' set to 2

+


+

(

+

b.zero;

+

z.zero;

+

)

+


+

(

+

{

+

var src = WhiteNoise.ar();

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, adjustZeroXs: 2, doneAction: 2) * 0.2;

+

}.play

+

)

+


+


+

x = { ZeroXBufRd.ar(b, z, nil, Dseq((0..50), inf), rate: 0.03) * 0.5 }.play

+


+

x.release

+


+


+


+

Ex.8) Granulation with movement through a buffer

+


+

// See Buffer Granulation tutorial, Ex. 1g

+


+


+ + diff --git a/Help/ZeroXBufWr.html b/Help/ZeroXBufWr.html new file mode 100755 index 0000000..b859cb2 --- /dev/null +++ b/Help/ZeroXBufWr.html @@ -0,0 +1,241 @@ + + + + + + + + + + + +

ZeroXBufWr writes zero crossing analysis from signals to buffers

+


+

Part of: miSCellaneous

+


+

Inherits from: UGen

+


+

ZeroXBufWr analyses zero crossings from an input signal and writes the signal and the zero crossing indices to buffers. It is intended to be used with ZeroXBufRd and TZeroXBufRd, see these help files for more examples.

+


+

NOTE: Often it pays to adjust zero crossings in the sound buffer effectively to 0, that way sawtooth-like interpolation artefacts can be avoided. See Ex. 2 and Ex. 7 in ZeroXBufRd help..

+


+

NOTE: For avoiding too long half wavesets it can be useful to apply LeakDC resp. a high pass filter before analysis.

+


+

NOTE: For full functionality at least SC 3.7 is recommended (adjustZeroXs set to 2 doesn't work in 3.6)

+


+


+

CREDITS: Thanks to Tommaso Settimi for an inspiring discussion, which gave me a nudge to tackle these classes. 

+


+


+

See also: ZeroXBufRd, TZeroXBufWr, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFanOut, Buffer Granulation, Live Granulation, PbindFx, kitchen studies

+


+


+

Creation / Class Methods

+


+

*ar (in, sndBuf, zeroXBuf, startWithZeroX = 0, adjustZeroXs = 1, doneAction = 0)

+

+

in - Signal to be analysed, size must correspond to sndBuf and zeroXBuf.

+

sndBuf - Buffer or SequenceableCollection of Buffers to write signals to, 

+

size must correspond to in and zeroXBuf, writing can be disabled with writeSndBuf.

+

The length of sndBuf determines the trigger for the doneAction.

+

zeroXBuf - Buffer or SequenceableCollection of Buffers to write anaysis data to, 

+

size must correspond to in and sndBuf.

+

startWithZeroX - Number 0 or 1 or SequenceableCollection of such, 

+

determining whether the first sample should be regarded as zero crossing.

+

Defaults to 0.

+

adjustZeroXs - One of the Numbers -1, 0, 1, 2 or a SequenceableCollection of such.

+

-1:  indicate all zeroXs, dont't write sound buffer

+

0:  indicate all zeroXs, write sound buffer

+

1:  indicate all zeroXs, write sound buffer, set to 0 there

+

2:  indicate zeroXs with a minimum distance of 2, set to 0 there

+

Actions 1 and 2 can lead to smoother half wavesets, see examples.

+

Defaults to 0.

+

doneAction - Done action to be performed after the duration of the longest buffer of sndBuf. 

+

Defaults to 0. 

+

+


+

Examples

+


+

// See the ZeroXBufRd and TZeroXBufRd help files for more examples

+


+


+

Ex.1) Basic usage

+


+

// prepare two short buffers for audio and zero crossing data

+


+

(

+

b = Buffer.alloc(s, 256);

+

z = Buffer.alloc(s, 256);

+

)

+


+


+

// analyse a short snippet of random noise

+


+

(

+

{

+

var src = LFDNoise3.ar(5000);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+

// plot buffer, most likely it doesn't start with 0

+


+

b.plot

+


+

// zero crossings

+


+

z.loadToFloatArray(action: { |b| b.postln })

+


+


+

// clear buffers

+


+

(

+

b.zero;

+

z.zero;

+

)

+


+


+

// example with SinOsc

+

// other than you might expect SinOsc doesn't start with 0

+

// for analysis you might want to regard the value at index 0 as zero crossing

+

// this can be done with the flag startWithZeroX:

+


+

(

+

{

+

var src = SinOsc.ar(500);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+

// plot buffer, you see that it doesn't start with 0

+


+

b.plot

+


+

// zero crossings including start

+


+

z.loadToFloatArray(action: { |b| b.postln })

+


+


+

Ex.2) Adjusting zero crossings

+


+


+

(

+

b = Buffer.alloc(s, 128);

+

z = Buffer.alloc(s, 128);

+

)

+


+


+

s.scope

+


+

// fill buffer

+


+

(

+

{

+

var src = LFPar.ar(700);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+


+

// playing this repeated half waveset at slow rate shows that the x axis is crossed

+

// as the buffer's value at the zero crossing isn't exactly 0

+


+

x = { ZeroXBufRd.ar(b, z, nil, 1, rate: 0.2) * 0.1 }.play

+


+

// this can be circumvented by two strategies:

+


+

// setting to zeros from the language

+

// can be done while running

+


+

b.adjustZeroXs(z)

+


+

x.release

+


+


+

// alternatively writing can be done with the flag 'adjustZeroXs' set to 1:

+


+

(

+

{

+

var src = LFPar.ar(700);

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, adjustZeroXs: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+


+

x = { ZeroXBufRd.ar(b, z, nil, 1, rate: 0.2) * 0.1 }.play

+


+

x.release

+


+


+

// If flag 'adjustZeroXs' is set to 2, this defines the minimum distance of detected zero crossings,

+

// these positions in the buffer are also set to 0.

+

// This option can make sense in the case of sources with many fast sign switchings.

+


+


+

// here the resulting buffer can end up with sequences of zeros ...

+

(

+

{

+

var seq = Drand([1, 1, 2, 3], inf);

+

var src = Duty.ar(SampleDur.ir * seq, 0, Dwhite(0.1, 1) * Dseq([-1, 1], inf));

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, adjustZeroXs: 1, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+

b.plot

+


+


+

// ... whereas here we have a continuous sequence of at least minimal half wavesets

+


+

(

+

{

+

var seq = Drand([1, 1, 2, 3], inf);

+

var src = Duty.ar(SampleDur.ir * seq, 0, Dwhite(0.1, 1) * Dseq([-1, 1], inf));

+

ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, adjustZeroXs: 2, doneAction: 2);

+

Silent.ar

+

}.play

+

)

+


+

b.plot

+


+

// This can especially make a difference with ZeroXBufRd, as the latter works with

+

// a minimum half waveset length of 2 samples

+


+


+


+


+


+ + diff --git a/Help/attachments/DXMix/sliding_ex_1.png b/Help/attachments/DXMix/sliding_ex_1.png new file mode 100644 index 0000000000000000000000000000000000000000..4093b05fa0e215c81b8f8c38491f245f6a3c3c42 GIT binary patch literal 11560 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 ZP(T2ycpL>YBpV$dBcUi>BWe)zKL9Yvc;Ns5 literal 0 HcmV?d00001 diff --git a/Help/attachments/DXMix/sliding_ex_3.png b/Help/attachments/DXMix/sliding_ex_3.png new file mode 100644 index 0000000000000000000000000000000000000000..24cfd8a32642433e996286b2cfd2114214438f2c GIT binary patch literal 11285 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 D*flfW literal 0 HcmV?d00001 diff --git a/Help/attachments/DXMix/sliding_ex_4.png b/Help/attachments/DXMix/sliding_ex_4.png new file mode 100644 index 0000000000000000000000000000000000000000..08bc72be4d4271241ef14e9af6faeb9cd55d5a3a GIT binary patch literal 11818 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 literal 0 HcmV?d00001 diff --git a/Help/attachments/DXMix/sliding_ex_5.png b/Help/attachments/DXMix/sliding_ex_5.png new file mode 100644 index 0000000000000000000000000000000000000000..ab4a86bde24cca86e2bd6828a09f49d7c6dd35ba GIT binary patch literal 10989 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 literal 0 HcmV?d00001 diff --git a/Help/attachments/Idev suite/XIdev_scheme_3.png b/Help/attachments/Idev suite/XIdev_scheme_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a8c42a9efa7a49bff09f09512297687cd717a1 GIT binary patch literal 152759 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
  • (Z#ZSAX84ujX8}<_nRQp~W6D6Aei1 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
    dy8xbcF%J}|@foBV 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

    GCC00gQ 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 literal 0 HcmV?d00001 diff --git a/Help/attachments/PSPdiv/PSPdiv_graph_1.png b/Help/attachments/PSPdiv/PSPdiv_graph_1.png new file mode 100755 index 0000000000000000000000000000000000000000..69fa58161372fcd2cf93841e835a5c80e854d29f GIT binary patch literal 68104 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 Al>h($ literal 0 HcmV?d00001 diff --git a/Help/attachments/PbindFx/PbindFx_graph_1.png b/Help/attachments/PbindFx/PbindFx_graph_1.png new file mode 100644 index 0000000000000000000000000000000000000000..c275001d2251bea1da42bf9b57d655b82ce47945 GIT binary patch literal 170908 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

    ~%<| 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 Olh3$_nWW#*SC48QLCxyvTf(R_Vv3YLLQ1_Krk- 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 literal 0 HcmV?d00001 diff --git a/Help/attachments/PbindFx/PbindFx_graph_2b.png b/Help/attachments/PbindFx/PbindFx_graph_2b.png new file mode 100644 index 0000000000000000000000000000000000000000..a92e6f2c732ed16b557f81d806be27c6c9da69f3 GIT binary patch literal 127450 zcmeEuby$?^);A!bBB6+MCwYpq|bhi_^sazyv3?_*(M5h=*O)4;;I*N265 zXX7qD<}3Uu!DuWjY;Id=X*C6DX+|{{M=M)wW26%t%e{*VNN~_fbO`ArGNe6k{|; zL-r5cA3G$ZGzIxjSb1N)qQ;t?U4M=z<=i7IRV%L{klcdZ#dZIl3w{^_cGczh(_Icm zk4IlnxLsU0J~%%%2<81nl83sm%~{{f@GyEP*x~&$#^1d8)So+e8u18^>CT-yc)jsA z`I^B?{VTDP^X7OX&1*NgpKfxyVkaMG>wmqLYNW({djHMSLNgm%+njq(3Z7wy5qx#d zy3?^d@WKQCX-LJ3hMFG_`Yk^2SeY_*$tAy*`xMj>$ad$>0K=DL1@1eYICS{<=;FJt z`K9skvHkHw{9Um+A!?30I`M&+2;Os&*K@_f;$r&a1KX=W(gO=i3QOVL8%;0lT?CPv z=CuC-%B1ScLx*6d>!AE+H-Er2x7i zeCICnP`bFI_2}T3XJVz*@PLGG;JL*0VEX0A0t2Bw$&nNmHZJME{n8$c!{BL_^5PNB zUB-`C|Mp7~?%mkDr~k=s+^yIC$S6Fm&50-dpDd73K1$#}Sl3;~C4KBqYla5U#}EFK zFkqH8_wWDpm{5HL;@ypP1x;zZ`VWGQg;|=-o&PA%<>ZX=!%!{7j(>kkG2z8*4$A#`$-#q7U68bj@{f`v_MnW81(qDc- zF*#3(h)L`|yzB3;QbF2I@G)_~eKIdC^Kk!dUeC-Vbyu0kXE(f^`Ci0>bimTg$l09g ztpWjwU@0f*Q>F!$GX~?*^lzmh!^ky*13Rx37vxz@nuC^lN7-GVZoD22(~elP>fSAq z3E|W^lOC8KeR}P)q)Guyr11?zHVdI)zS`3C1{(t-w(w<^mv69wm~myV+<2T=R-l@K z3neRW%L^2?s(`dOOqM0*yDPBCo8e8U$@xAW$RIU!k*S z0{yi1GnbVKl%_X;zc5=Gi&wKZSi8;al?)n_3el7Q5Jd}&}9O{W^?RB+fQR(}O2q*jPm^yg^FH->NG5C4Uj z78LR1x0mc@<{;CnU|bQC8B*VmhPhlGLGIrQdjsy~hhu?6jqE=8F)jsQU(sAlzkdGi zUy5J9gs|}=`|H`6Ist%eMNu8WUL7}hOxKEH2>79Var-Yl(Ct1zB#)+(_#|h;Zh~aG z^dpB>G7;gQ;t-GKN2GCxHtnqJ|9+1kB?`t<#tGo}8`XP3Im3dJq>c(BhLiHm*A?P8 z(*~x8{&WsDiIOYM{yzDz`>_Mx>SKfd>s)`x#F}myEai2H_!oq-oD`#0kx$7#o##3n z9wC%RpDrMAXXH2W`3j1bMz*A!XC2ToGV@-=+Og?}9 z=3gv6;t``fS6)f@po(75c44gVxp)7;_F}-8U7O>jtoUQ#$Ml5$2-Sp=)<*5Ct}nlu z!nF?#-xND*a$hS|;0N_lBzp{O+QQ>Zh}Qm%+h7INkYSd;SMue-(^u-Ix(Bz{U6#|v z*ZapWuIC1Rj8q-Jhi(^-|A1FwHU8$90bI{?K7%gqQaqKJM4~y^YAQwp#Fb;=6`(~gnTOX zef~^sgYs^^+S1CQ{Cxnc?Z2&!@)$63R9CC+|Cwt%`ld7K*Dp$kM5~|tdA}exvac>? z;Z-7t_tF9XB!mVX;V}7&PzmKt`q!ou(l|D&^Ex)@32tt%r#aU5TsN&J6w@KRO2Y`P z8w&E{?*yHazsd-WT1!RGCysqkWw06OxsO>Rqc*n0+b;HQkGo2#?GF&9Lg%M6)|9X+ z_Nw-;SHl-uO4dmMh_k5Svw&<8F5~8!?bB_+?ZR2_e(v898|1@U=(71=3i&?UzrGJ& zoNgg5hKuVUsto>oKJ7H|*L}17O;h~_#^pS%WLd94HKq@5Rd^v$^&|N&Yj%*k+jVX$ zUQ&p*?UwOOeEuI)SChLqh$A@}_7q9g>XjB(>jK~XUD2JJ={TRFYr!4Vl8Y!&g7cMf z-43tk%u;70L4n7acZl@oD6{?iXu4Fp%i#n*c(8DeKq0Tb|24n)S(*Ft1rngm!> zLdWLJGYfjvlpg;h<_8&0%JlhoH9{|Hb9iU4X%zw%oIh;p&xk7;@w*Zj>L2pR{kc0K zpM+dc%Mw|X~|5zE%6a(D5oij;&?=!wA0oZSRZiG4gJ+Al^S3-E5+u`|I7PAm|7PCSkdJ zZIiEPpmWo(FkDHJO-Wg=#m}i)EL5yo#3a&;8mU1gpDG|Jf?$EEuRHJK)S!dkViy@; z(^2pnl)@nDZ*Ro^0_(M%oon{hO&EQ8-Z(u zk4jf^LZR(*Vy79XEelgApEXF9`s^3kS1$WMJZk8*ej{F8pP2CtjkPU%H&^wDY|%yE zKx^a4BOH7#52TXLYj1Q71o^tuOftvhjDBCr?0@vMv{sXD^@ z^(=_n2yWC&?$wI?VH~h5y!XR4YEH+uIl(7)=b`@|M?oroj;Q#ew8CaRi?ew?wwuw=@?rE2O=7v__=l96V#`?34rY6UC;xQ# zCZ8k=pc)g~h89ak+fo(f&Pp1K-$(0TI1}d1`!DABI7DjG4;vvU6m#Y#zrmDUbt@C8!x9Yq8T9F-0MNGv#`foA$ z$zXdg(f1L=*HKIH@KoytZ5lqp#c5KJwd;5N3>3{>$rioP z6ZM*g1Rw6H!)lmWQpgkoKXOua@`Q3PyGctxeQ_*~w+APbghJEVwts7m7ta^g3Zwlf zi9L3UNqllot@Acx5sN;z#YdC^kU5&X8XaWgEBk84XW^kusEw1nosW6F)dP9O5^JFQ zEbyU1ML2JQD-S%ws71+8V#c3Y7pZu9b#M>1@4zsjb3s6}S3V(dkfjvhv6+cDK3bT5 zZzmGsxa$tA5S`H=@AMV6SX{m*K)2oC;gtFGFBJg`hYVLKOMO@3Am7~EdoR;;WXiXI zjHhp)hT>H%6TyB{zBm@uJ4Pbhh|QcMbPU21@QpJo4An4}De;PEn79gasT8h5XXKr` ze{2T@_5|e4%FrsOK-&)hJnNu+)T9UW7U4DQwlQ*p(go+=|1 z#>R{tvoOJ(XBl;Tp{5;VrvjxEsBbQ@>Z^12Gh9=hG~xm|)onq{RdFYYvd|5Jkz%}Vl{*Qu&M=)_SW!iT~fjyai!sTy`u9KD0K$>;QK z`_06=ugEL3O*q4Zj*!1UjGt>+L0kIlJvZ2C$2-8`>v}0(j3@P{s5CI+Y2;4L0(@pz z#L?%LkE;@SWA0<)Go9x%(}7g{fy+POFhQ6>EZb&m{e(F5e>x!+4nU?Il8~7Obq}1@ zWP7##2N5u2mkQh;4=d2c#JD~GE-AAh+b-?nAS9y`XojPgIMJwH7B=alJ`U89IePWhjY?H-5K0TyA``wQ*ZVww?#yzB1yEEPns-;QMey|lB zx@jZr@;O9CNGdIHFeNWx>=`lBZr`(Nsi@(t%g761ee0ppwxZ7&z0k8(8J9*j`xloB z1=+-|#k(-8pTZxKEUCz&YU!6-k5*0c#~*>C&*oelNDL{szG00i{B%uVw0a6 z{j41LRu@O-NrW3pDUAr><2~TAKD(EGKEMm!Q}$@8E>+`@+V6wd=tW+N2O}2F2Wa>X zI7pC=O0QGTMO7D4t06lIi#P?(;H8^W!iN??eR<2j{>rCcx#QaT)d5!*I3zVQM7j&} zG2i@%#2iW^or1@AF(5JdaZs6pFgt+^R?t_R9On{R-+UX*xbZVl&FeA~{t&5PsZO3f zudPq8qzzf_VfiGx_pp?@6M>x+X!i!FyqvB=_IuMb^)_+`XO%3v&XB|_JYMpe#potm z=fJ%Me15JCrRw+O?~sagD6Q9`@Bphnc;3=zu+=xVM*?&=T-5hnI~$s!1yZI3Wq!PQ zZRs@sl=Zf|A}+4o_;x@CDPl4ybq6wHJry%acGwFGDI2Y~JTWJXKJk(6bZ>#wCL>$* z7Oxo=$6KK?&M<$gbZO@&>>)$E(0Oc-ZtcsEV?F<`(>u~-_#&@Hnc5^_jJewWML8Ow zbuVkgWm_+vUQU`aY|S>y1@-Wd_fl`#yXLoZ6sk<*OfQ)Nj<=&2G+ATU5nTgu6;I7b;Vr)P!V@Hq~UNW_jk0(y{x9NnHoJxj9xf z8e$l}xllp{`xt-FcAYq90A`ErP3$=L&OqPHlEe55XFLeC|Jr-8aLjPl&qOpYd#|?Y z7=poJ%}e+Qr_ZNja<|2|%}#IH_C<2C>gb}b7i>EFy;GgD4OBUYqWvfnpZ(D*x>%(G z>9Z&dnErT^A1(Er0P`uP-KpaCXYf*R>Fw3$&nQHPPxL2k$ipL(v!IENjt=zeYr}=M zKqn#dhO0Zu4<{PpTkF_n7@Q$TgrQ9rGeyq)Sy~-{nCe$tl}ylu7q;G?34F}ux89e~ zDX*)KH|^>gH;H3{*OWHr!k_f<5u&YecXE2~shH>r)|h zQ?ClanPtcO`m0yn$*?VtR?|?U$~;T4?X%CTaL>TNineRD(fg<>w$EA@2#PXS(_P_* zJ_`&R5BpQeK=9-cWeM?hXoqyr{!$mf;qa~M;jjIxY;sjIK@V+BFX`2YU?@A6 zaSYY4eD%u4oR;{CV`zJlVVnOsX=h`mDR^1`g^8llG=!4)@dQiH)z>3^5ua=~2j3o- zxiio-7!i5j7!CK$m#A%p8Bo~^kJ9f}mOo!*fI-_fHJw!RP|(HIqjwS^pp2sPMvDHx zT=z+rY^E8}qo3~gJ_ybDHj2+^u7?}KoX?EO#l(+@`n@!b|JwW8ACrAOr|O=5?DXzK z#bTqNkBw?Yqgdj##q_=&pSz*c+HdAqeQXQSD%69_Ik6ZK9Ds7W7rp*P=++2e`dP&J zX;ATJR!dB-^WdcNJTJ(;`=LxKu%er^YxJ>oR~*2x9EUSOy-n+z&Mdt04xd0<>!xxQ^Dw5?W@SQKHn=tga#i+lbkpE+{|QRA^_T5EG0SXO8hQuK!s%LL9@gsxH)3> zD&*|jbQ{75JiH8e0~|N8pt*;aSw|~O2N0#*C+c$BYx6-w8>6s~-YzU% zon`J2!j0H_kvX#DOdF^CP|CFV`N#Y9=+fwqy}n>AEtBJp-XTSbo+ zuee|24*f!LHy+F{xl+P~5Nc}@O`XSVR0-xROciQsd*iMiWrUOj8zGZ=1cHIEmkFTR zB7kq%s3`rkYC8bj9^9!9NM$%n*1J@k^2rw1@yMfz7o;0IELUbvCHH?ntJhsxv*=iI z{c%p^G=hb0-4Ro0)$hl&+g&6yZOcd3g7tpPSP2e|uPAfcg^l;p{k{~Hh0n)cTjH_J zN>ZP1O@2r1*Z@^_1N$lz8d{w_GtK-P%UyKfX%QZR`qf6T48cfF$HLBPCACKq_iI61;Bc4_iIRTa5)T@`%XcK*=2^GxAGf!b_PQ)bpFgX#Y@xl1p$-Hv!NMHbD%AbMnW`qcycI z&=O%&+*`BrM`G&%6sQ@HV(vR(q`enC(e%;B!5$5Bo@HT|;qy7eNzlfr@8phoKIdSa zfR~F=q0i$yw`IfmS5i=Um%{EdU3ZM(+vx#S-8cLJQ<;FdN3Nzz(0D=}vFE_9Bp{(z z;@cqh43Vq&Fc%BScMJZdgV^tMVvjZH)CT5)U*kDP(2KY28dMeL)cB`w2P}FZX2?^V zi6e(9c}Ec1`-SJmU?WP$cHMG%&?(Ke>urz)kB75fu+NW$$HIt`JFHia%4({Q9nazW z$l`J}b^C`wwYEw<_XVLX3P8^!_WiOi=#9SoA1VS$==#cb{8$aq+ zlRxO2BBX^FPafqYvkb*^mf(0%n$Xry%1LhRV^6P_eLfn;9wErc3XIw>j!0jC78s-I zt!xdkU6L+_Cd4^*KgZql;=IOv^`S@DZK%K4dY|3Xdw>nhnUO%MqTQ-Pqa5?zJH4P|rgl!GM$UZ%rTCffqF`eGZ=fj?Fgq3=3BtVD_(d6ZD|B zdiwR-R8*^ya)QdMZBuB5A3_@!nq>E5#Z@_!4>+&5Rc3;c{^_{3uig71+qG{K7VtT5 zRf__^45GN@TU$bulA9#0e5+Z2pgA+@NwA>Eyeh2Vo(~zR`BrH zo81xpJYy}&OR*_}8e22kAbS5cHR;d(rzv%_pqcCR2?|*N8$5(05e&isev82qVhn-;_qtFON1L_-GCMa!d3e1 ztz&Gfp-k5^c{5cX^W=D8rs155*ynBSTI=QGf!wNMzhGgwuusoJ$T)(R- zqaX0yNWTS?)59;wt{cxMchEoIDPK}g{~1APk;%qcHKX;b(%aI>3W-Fm>QgTx zidf(zO05ejg`rx`A0^^qrhhioHN1u+B)7 zkiX6NpR=+~Y9G<_Z=QaN7SMDm70>1_iTf-WoP<=~Dt_)T8Xx3}IOB)ZXVtdyD0k{(K$q&)oYE@3H zE=X=D&K&6O8eocr^F8yq9Um|+@PsQGUu#UH@nf6H{rEaRCKptX)A!|o6F%bTa;K7v z5NnpXZV62A4$YspbSbZ&^NZ(xvLUCFu~$*3L_GmXPD8*fVgr=XR{Kl^R?v*!isT7B z4~ay^3zC4lzQ2znIpS!ZPquck8LcMP3U2Q?Y;i)Vt@O|M9hCfVp|3d^>n4lrWPERV ztU~#G^yznKVh2Z9H|Nc=-onjV#49AC#sc@^%!&S*(Lx-roX}+pJ3@tdy-`TrUV|NB zSJ?v-;dkv_Iy zY-btB@!OlEysLsKm64kR!s+)st5!op+!Zgw*BW@mcToBpvHk+HDDSHaqQ3jqc8jt0 z4YLf`xP`SJIV6si_So}J@8$56n{!Ns(m+{fw;D)A3V0cji5RJuGSPB4Eb)1#`D4d)d% z-=r*C{y_T{m4i%Wz4&u{HL#&h}1_z$FBI^((LBYDnMUh@X5o z^=2t`%#Y>N6K3w;1}hclBsrK9kSrQ@Oe%SGqg{UV-QT*&t;2(~@#WC)h^In@+1C!l zUh%=M0^RW~*h9>qNZ@4K1+47lSK`0&5PUO-nqC&8(%7Vd*r{T)Slikrh#x1AEX%uj zT^}`LCtkm6OwRo9mEa`QBw7-k&S&k%2>*EYc}@;}MU_CVw8f3Fg(Cy~^oB%X#Z&t% z%Uy%|-XOnR4G#3c+jV7mhm}GP$OyfkK253$yS1MH*h(y0wEtGaK$|&`VazQe*FAEs zhHr)RzD1Qig2Hb(aLfAES>3EVJs_>MvQ}xeSA%l&=yMzH<%>o^C(oYX)c3tR^$9+fxe3jPhP{HQ>^n0kjf^>t;o!d&k(poTE7?g3W zt~%gL8+2vltd@UC@ptD=*S>C%b?r+cNrp~AD@+BeS77{wL5t&t*^)CWfYBY#XK3JV zJ*f`*`Y#+#$Ie2K{(*ky47>;wcU!rB%wHR={Hk`dv*;6S>$0{NJnzq5>t?>N<5n@} zB-V6wmoEXnF-9%U?d2o1@!;L!;m?@tX@TfgQ@ND{TGY&u!|R!cH7rk|mEX7_Dm5Sr z>M(9eGB$kW&CDW!8D8g5A!8c2PR)sk^l*-lkU5;Mvma!iws2+YXkQ@UIJNlj^trzT zF}`OKJYynfJ)r~OeCiom(jtKRoS=QVzm(nZj?DmA9{pl^{DGbChKou-lPI)lywzXG z4@4(6Wgb{&gW8=*+*)$yjxVc>ifwj?w7T}8wK&zi`KwzQ)P?6GdQQ1togz^h3gLh( zlIR^Fnd={LMC=BzN z^JJYa@-6)osuHc>^p+$1d|dM&Mu{?uvGWyaH5^$# zBSVOo&y;n$31;QD7{&oPM7nPYU6-5*+K=YK9buiS2Rad+O}k`GRaV)qZS?3FrG(!C zlyW1{siR+r-g+B3!Id~5p#ayBfFFu*hRnj)gfx)Va?1CoodZLy-ul;mH=7%Lof$(Z zA*V^il?jvdauFQt?DnuG2TEK4<9kPm9FM1rQqWjKf1hi0>(B`7RMJGiY(V^8Gq0m{C1j^bL=ZB+vXRqM8J>3PG3~kSW2w{D+D+dHR&Q!~FyJat@CZ3aZCU$F z8YixzztN##gIesKAMK<6={!M$q+1h&z=Nrsjdu>XvK(e<+DU^jscSqi=TKy=Gj(}Z z!8Jqm2BU3tTNA0*x``XQxceR=Nu?7<^!szcx*~}^gcn3xKq#=h#^Jp9%(O+Ntx*9_ z!4D}idilv}*kDgee2#Uj(fgYZ7yWpt!4pvzi0@Sm70j)$7wTd4ZCN7IKVTQer{krm zHd?Ao$a{j$GHMtcaCKX)c}nM3r8%&Z4lHu#5cerP`g&e&vL&C9Ht@X!TD&_l(dHv@km z2c?~d5@l<{s*!N9OA2B3%Uu3K6Cm(LL6|3Y657e4T{?ZPT564=;E&a&a$(`6awZlA zOgb0WgXe9h1ggU|)%Vm(huj&}E&%RRTv09)PVeMyhtWF53v({yRyL>6X>$u}wM{Q) zZ;!RvFK@uB!~Gb%4qZ_`QmF|+maeTZOom>aHoKQ=<{ul{!pq=_TqR8w z;m2eRY!Yr7iwe#k=WWt#OZ9S7n;OqFXQEMZbzjdQaumMC({bwq8pm{l8#0S9e^isE znC0*YJ<6+7+D_%oXmw!cGq9Q!L4QG^Rz@&hQgY5dz^=Q;e5^eL!jC7w#-%0yHNG-Op`|6LN>rI| zu#nrPuTDCU7*p3k>Fun~8TrUd;F=7u0Wj9rQfy8+@;T6CL0bvf3G*(~hUtIB6>tJH zZ00+~cjDSeH_e|#vgS9s3-}6dL8ZX=l|1W1RBY>(lUky|gG*+k2n=XzK^ToTS=*;3 zLw^@8_Km)HfBmexrN_dk&MWkxAdTo>H01A3ahPB>(m4;;%m>PQ4a&&}+J1a$HgN02 zjH#h+x5kewKz0t$>o6bt#sJPAvyf$wC6(ZPb#1htxG8xz`a&fDRpKjEAOk>6#HGO} z+6yojBKl64!SVmm_Gblifvk$zvUOVXC4^0|E`Ns0Ly`dtLcWvVnk_ylVd7a+tgezd ziU_Jrl~%?g{*7351`+2#1cyp+H_V~T4+FhcVebRbzC>rY)rG| z0s>#6R9=Apq1P+Uh!2RvPVulyRco)@CYax}_S+#)p_h$))Zk@vM+o}tLm8@`U-T3C ziwgu?1!$o6Xt7s0xBdj>ZFNf27h7bx80(uvU)^(QQ%$qkxua-ua8<7TT(}=z*>e5B zj~*P5Jz9~8A(xmTicf3vhE4HAL4A*Yv1<eCd?^S+cnGk~Q^Bz3a^<{nPs8xuN%jC50WTZ54bXj6hb7nwN@`77~ zbmqyPU!iKR$znm6CC!7N589P9em=H)+1i%#n@4HxMQ1Y2C}sTOlSQ8bHhSjGjdM4@ zO|sX@mHNg_2Dk1A9W6>{-Hs<`8R7+ZxFw3F(()bzHkEF_TP+%`v)Q*8wTZABS|b~+*@rgL>zRF@ExiwlZmQCJd>G8&ntQ$}8YH0&RVL{(J<%Y>GyhEfcUvf z2LwWF-?e#pd#=%e3lh?(@DWcoeae$}Jt!>WVMv9T+TPS%k@p6aJRun9_21bi6+)0n&X1Q^IpA$`;O}seZfW(~|p-S-+f3ab=*K zZVD&}hfn;PMX~Ey3u=zp3~BF-ZU^kmRrRw-an%?lx}1d9*i8uFai?pvG$<5x!$ltm!viJ=#9<-}!{%CpGIYC)&l3~7p zKb#5gm(j4D_W8?%MDXO3F3Zz@BB}}=O1*HM>-o>0P5imkj{H}*>q7-_9`mp zlS?=heDO7+QgSE&PvfC_ocTG8V+wNX;nm1HMK1dvMK+>JJ3be+MNeB!DSDo8UQ$nq zHv_^6pGDT#05}_h=V~Bwk?OJKGq5KXYTF;@NM=UTc8kw}2Zi15KQKa9_#@{4qACa6T z1`uLAKdTl4RR%$qPgpntI7~*q>&0Ksk!44s5RS{tR=#>bF(tUIst+Prxq$RL9s6xj zxG^QypFtCN*mG*jwiQ;ys{1ot^whsia)(O^2T= zQ?dh*7X1m690|h~?9OM8&ef68bT6E8a|wqM0gS&xz2m1>s%!%AqM538Y&m|EJ2Y`+ zL?V+enw!F}{Qe=WoufR9ntBin_i{6UsD3W7)^ zG%z=+D3RqbXvB&+SFz#6bdTJCX7YwOB8?8Aoh^^!cxqn|dg|C#f%*VynqDVw(AU*| zVo9Ujq{w(OlGC+gQIaV78r*f>KQ%5_)~A0H<5*q?lE|)3E3>8Oc`lKk)nX%Q@Dv`&0K^b(hutjuf?|~COz(-OaaF46;g|16k67EaCm-d z)lpWBa+<1Pl8JVK9sdmd>QEFtQo`y+@=>N&I`Yy-mm)Isq;1v=Z%G$GMP1ie%Ol9W z$S?W81GA4~rJ_iPmi`Pcgt&%u=;7WYso2qz=#Y>E%D z4n_;be4MTnZoHgGvhw*#$y^jTO^}nb_K2#`VfS^}<~nE5qq`UdT>cMXAM8!BO6zO( zmU#YjoSLYnQfxzlt$D4wCO|G+V5Ib}iMyo&uv=ov;EjtyjS9R5(D3XMJ^$Qay6Tth zc-@*8eFgsRjA;w<>&@YTQ1%JzOn6}wKB`&jVH*;qdHd@pZfkf{x*W!e#|-4ZLfBcs zXc}Z0Iq{+#0^jn-NP=XB9J3u#0#0Rbcn8x$b%=j7P4DaYt5>hhce zFR$SzZbs0pK8~$b$X^W04BzJfDD`tWsQ&3AphCSI{WB6pNa^^1X2Cl|)hYY_LlPu9 zrCVo0ZVlI;P9Q_bmVF z{pBECHBcpIk!r?&OZ)_BTr33ZI0o@1u7#=EE#Pp-Gm~B>SpcwW#T|{t!YcQLRB1EY{BzxKuu1b9}^Vw5I ziD}}=_<4FsC9U@pg9Emkm`-*$F}+sSRILl0@cdVifX3;Vc=>;_>Ph7_O|#*CBaoZ4 z3(;e$7r@~R*r_#4?oyG8?z*#Xv}NdNa6s(tpfy;LKpu5lh%l9qZA(XCS6|xLR>NBM zY~|%pwG)qj0a}a;hy|A52mbA;!!@%Tq3)2a$p-!PO{&(gAx>CghA3c~t86S^gXaGF z7?VjxQsa$@!feXJ1C7j~HIk*`sTMrq!9d_Tv-N_%#ntg)S%#4Nu>RINMk}v5HiKBr zK#VsoUGWi{q?Nq}pu-6x9`k)v#T0!kC+S@-^F>KzMb_}-}-tsqOSeFv!L>@{SNeX`b6 ztwZrvMK@6HR&RjV(Z%$tH`#UNS4byAYH0Q`7bZCpvvNsA)fGD-J0#CZ0AK!5aLRP z7Eq41%i6vkv-75-beVYb{O|YfZmF>rh1}sT*0_O@tNzW2s$aklC}V$Uj)8_FBt8gz<U#>-9-tvNayhTZ5wI4a8C|+s!}Tr`pd+^xN>O@5P=tdTDJ=kLbW% zlUQBuN!IGDE2cNUc^vQs+4QA$Gu~4hy%{+TgN0>n5dbsa?{Du4A4M7aHr zDTf&tP!D>O;g4xOx{DO=BGM!GDu#|Z!lj=o0S=ZI&iQ^X=%q=84?z8H*6z6@yy8Og zYQlBlT{X6yJkXr;y2Yf#jo#FB=ca)m_B%eeEf;RBn}R+UEe`H2{<4m3?y}fzi@FXL zKl{q~$R$$TindxkQOm4!oR{gj=F&dar*CY~yGmgy5iSdj#NCRhO?Q#1*W$n zdoOIwYCP4{%dVnofBgKuz5_v5+KXxdnF~VG%3|Vo7uNL{%#!>AA^4slzA}9<=oIXQ zi=?5p=N|tE=~s0|j44k!@My#eg9eT$g`ptrjwHa7z_wLR7> z>GNNQ-95I>bWEm3i0g_Givq%LoL;XjQb$CDGU2SVr?2jQ%^v&oh8ILT^x?|&0wZ|| z)Vl2&xYV4+up@oV(iq0-#7hN-#UHx&yuvh)1zFC%IuyR3p60n6Ms6ni?G>_~w2OhR zsdv*Q4Oz4Hwm?a|dh549czewXW*V60xlNn**|hti;RA-sGOQXo{WA41dxii`{o7`I z`{~|_l^dFpS5c`t<&N_pdi?U=KqUC-XQJqhgc3v`tRl#E>Z9@RYVX>hPle(Wo*8Fk zg-X})iLJ>S>6X8QKXARn0T$UckY&FQNYe8;tbCvL0Y|^3%bMmZ23J42#`=)&~4MX3qK-$+_@T`x1c$WQtv+*Bh=gwSLVd8` zF8T-4SPDtIJ}#+K9M&5bhZ5!fPwi)qwnR&MlO~g+H-H+-DYiahz_}?3&$NlVk>%R0 z(v^NtqthkXl%H#p`cD^OpQ*!Ky5vhkhv_GeXT$C92)(`5+`Bwr4?Abd(hJu#0X>KV zWE=?WMO+WuJf)l8iMzJ?4Aipre8&Hz_=(;VSn0@!`=&pE1>I<7gjgK33UZPS z8_s$4vI@k>DeC^VIwPr|x*Eg1xW)O{Xqjm@RSF3dzACc}S&dpu?8r@105ITR!re&tBO8qP^Wrd-K%uj;jfE ziV>+SL%(g{*}b0hf(|aWmMWEKq(i6Z3t(PtswKNo6Ts*-37a*l%KUaB)fvuX@iD#m z%*Q2|jnRqkT2H^x*Q7?!0@GdrQdInX^G#>TuTzD^@ElRn>`urRTQx0*_f>5a5?hb+&4zP0 zY#ns@6R~cDH(q)X1jF%07GLA_Ec=-TFqb z*$eeA1S!E?3wx@L2PVfJKi^sqiEp!lZVY7>Uk*&~Z10T#573`QyqwyMy#k6d4Vw%Z z(wwW`ziorn_9ZguXqWp6G`{@nL*YRmaEJX4;U7Fa_gcko$E}96%x@1hxyNa*rvM&A zdwmTh(GIplk4`?=b}=BkGYF$~*0rE^bFNZB6D`!l`{RXYz#-nlF8}Xrt(~Wj6Bj*0 z9isMt&>7y>hXyIE=~3dveGB6tl=o@tQ@x`>q=6Lzs&u}XiGNB0fh#x66(n`yKWf;} zX&D}{X`UAH!bs1FA19Iw)E-K;58-T*l>VGH<;p2CJ_Cjg!XpgQAgKV(k~E#y4%=N6 zrH;2b`}Z8w(Ou-L#v|i}ZI07@X%xC-i75<2{K!c$5sR{3rUTA8`GYn{?Z@p}1+P>s zUlpLtn;LKJ-UFTb4M@%AyC!XcccR*9cI;(=c})hF4pN^d&npl@?ytil8&ZGx zpBA_^N9sSazNOy#y&V)yE~L_k#3|LY1ptg@49E68Mp5{KI7l-_?|y=Famqs zYppBJ>%7kECJMo8zkc-fTNS}y(+z)7?o24Q#%D52vC@SWulIUgyAF%URp-A+7NO^U z?%v4!gXyd@I9g6YM{{)R15Bq`!tB<>CvsD@_~WUg3Ug=oEcNH*7+XgrJDz9C-R+(I z%;gg~v9`A1@p#`Dr$1n|ZuIyYpo$IHQU+D|9m*keGF(jp{YXy7^k*h@Iyk@CEe3Ez z!4LwIu-8tpy-gb&MON)BUx%~rnU<~K#GWl0!#b6Gbc>^}#kq+bsJJG&9Y)uyC786D zf%H%>{K`>kla&*^+yMAHtYmkariFXpgQ8=7g|@RbZ6X+B+SorSd0KosBU=nlb~?K; z7XQ6MFY{pDm5r)CjPNUo^xZ}(jLThn_dgl2MsSy!X-M_w$VlB1XDqADng#Jw{+}I8m%$*jnaOfv0ZpD#m{>GkY_(bQXiJ*mR0X(V{=RYPV%`@7{RTW1Km% zgIMdy;&R=ew1p!Ws_(8|C}UK+A^&vdl{PyfbS(QsVzxGnbo)_E`Io_scDuB2v$+&Q z2B|13F>$_qxS@(CrPXwhz=G+-liSmw)!~V2Pf;V_H`H+CpUN5cHtk%KZi?4eJ=%iZ z!7W`hz?0>;>b|6v(>vc3l5028^bR554Kc196;_pN#ImXi7Pl@njfId=UMGP7%^61{Hx9rRW$b4%HLU-Tv@OKjrP z#o|Texx;KQN*BJPk!G+4>(23TZ7Z(GIo5+=?Uur@$uwSuaT`^ydp)n-9hu-CxUXezosgUn4kN+q6qCoglM+ZJRVA7wOF>(WWTeYsw<)vKr(3m_eM} zNpo+oR%bq;pG_?*GL;+A)jRa8&}ppG>0DXJ-zhvvZ$Uq}!Pp4+rUUZm&GAcn2d+bx zPD`AwK8(k#Fzvm4uQZvb{T$Ytl)SH>EkoJazUN_%x6bl}WGcg}THDDS9xhF77IsG& zBer;*@;eXiVCFmrQinK@Pl}|rG#RYB2*aJItL_uxS}rCU5otTi$TVST=5v|*@^u?4hzDZKc1oyzu<;vO ze*3MvcY&0sWMiSHz@3VZcBBvSPRuA&G^?2 zO0tItm`$l|ZZG79)~AS{a52}yJ{Y}Uf8B@pXerg$+YBl`yONWTtk5jlYIY4vE(?Cm z0l`3$6QytM4>k23Q7oQ{N~!is#W%$nc-)92T#_@0Fo;akuiO}y-LbG8=%|_s5WIG> zW-$FOeSx^MG3buN{kgF{gwJpZ@kZ)=mMx3-xYiI8vsS%yBSDpYQmS&Hw%$E$GmNmw zHv{gvs{Gs$S|^{WJ4!jG8Xg(vxqc|7-M2R|-?AyPx;cL3JIN14(s|UDEAwr|BM3?T zQqp1mG#!dS*{;*oQ#K_gwKT&{%2SO!9IZQB@%U!^I!AS;0mYOqN_AbhQW5ygk927# z#uID=;k+@HY>CJARv21yk6hZSboxw3riPQp@Y>7!K5T}uleUChP{~~-hgp1GAY8?a z7EhOgp??)3EyXhR7dj@ZRW>FcET75ar}QAdd1n2j`i%nIxdl{zHdRSh+ecTYNsn{} z3U`M?WNxOZ?+BjdUHfGt1WbKZwhcDX-a%msZ~Dm?$I5&rCx+2u|I&@;a-~bvdqeGx1N-$ot3oi5IeMAly_o)p-RdD$5+U0+ z7>hl9>l5G4MaYF178yEFUgP&tOw%&4zkWZR&ler7?UgP4gR(H~aG3=e!;?yk2(6D= zpOPH3v_h)rM9my-o4`8<#2r2{WY?=j6s@OAj@ybEN_#hCQTl1zvIkGGLwu|)KbckSaU&IdA=$dv0`fy6nlgX)kMKn)j>`vj=kiN-O zSXNMNJd#t}iiq_iSQ33q16#Ev%^y8`T2-XVEiS9~r2Hn&am}J=3|_MWoIpML6PO1) zzdm*lesZGz^!%vL#k(bSx@d`bH$CWy@;BA)!Ow~vg}y8I9?muBq~a>P3V-0)r&{=) zb@a4-IeWB2>}KG1xH9c!h3No#PwcXXWqOgBuM2Z;7Frpcp2jZ7sv;hKP<#-+FK+F* zWa}oqkYL+eyEMVKG_|yJQZe0gTyy3&wY79&E9B7YJ~@1{oWN#yj9J(yCOs`1I3IM9 z_ZD*jp?Aww`{12-6@ftjV?Vo z*L{7CwFXwBj9W68qP8Xq4I{tK(ladY))*vQJ06Qd6sKxui|Cm%j2*Arkk50>1=ZJ* zy-7`&yJ6K*!laR#FyUJ7##Txvob(z)5m7FD7x!}s`t^)slt6X6NAOUAV_8$*n7Dy|(3|EEw#xt>7bkck33r9sJT3P<;o(@yrKGwAMXUSF_WkGA?$f;MTp#@~$rHspeza zSK~c@sJ&3bkTsd{%zrr=meuj@wDkM@)obH+CSk)mQ?M=Vi>m3DuTu!WICmZe75(~% zaFS@Nm3aC}dX%J<{n>uB0;rAJzSpOIl(9lJVxyT7HW%Mtdl7vJZ2-E&l-U(cjPsBM~#-Ti67 zY-v{_$HP^A_e2MNyct?e0$C|C^%ouzss2nWoC=<=5~uy@3CrOO{d6K|dzIEU0-oK4 zg=Z?ZsERPk;At1LNG^B1`XRK6N0E&4T8iJ7oSz90@7QM(_C}^z4|wiNqP0(|va|+< z88_X{q^N|k8eB%*;AF3gBLARinJ9xzAy!pOXsZ+_ga2m{cel0(q z-7iJP$!9W`jJrw?(d^UT&CRxD!Qlf0S_1)|X6tZ8)~eIxk+)L!Z8Golo6+_9C5T{b z(~U9ejb#*bOk;Uhi=If;`)I|kCxxzz+$xiT_qk2AekHV)KW3wKcGL}?uA#P6IJ>aj$Cr~1xKrKtXLNKe%t(+W7BqKZm|`U5Tl7{=b&faGWou-On1iMQd~--=PJhz zJ%!vF+Uk(Y`E$UU{x+*N%I}LDG2Zi4?zY2B%y>8c{sx6`k{n9l>?Ln8qZM<9tF^NT z)u>dlgJitzH& zbTagi@G+2SMW#Lo675WQe>2?(LtT2GZT-@8M|5otqKw$8rwSoz+>-6DlIxj_kssA! ze>O>_zu3-Tr@AMtz8TXo5w#sn!jYIio1E{;E4J4br^_)%ldXEkqM>)EMrgPhu7cG? zbVtBkxcsI0l1B4wBMasD-rXloTn5eU9|~FoG@f`(&>gmOev4t-@H&~B%8Vgvh@btK z!e?Z_5Jum-qu*`k zTe*rJy6-;fFX$_%r9m<;VJ@Rybeu8mEl#Es8NKuW zR6Dn()b%-Bx8gWayPSzE-p!uG&D8QdQ)8MAe*A7nLO6_fZ&Rpg9gDJTVkf)tY(9*6 z?uC9(Af~g{TsB;JIEKhoXwZxxU3wj7IN|+m=GhV+r!UNfZcnDOE@7mWy%gAg!K5~y zEPHy?&^7($nnqcmcBW4^?kt;qi!ED*tVS-8KJcO@!yP`2Oa*n5<#mZ42^YqXYQ|FTmL5;h!PwPuohRFJQqxwJ_0) zy{**HVI`jE9n^htDIpbWl4!w`B#eE{L3Lf8vi_958IQ{dihTbuNiOV1@R#*x;U3l- zk7GQp``v_1lJzMbZP<WK4jizR+OL`Q)e_>TcHin!iaq z(oWQ_-#n}zFys&TqW4AKd<8f2MW6LG5lghrK7_qkeUTS=;>xmrX%?$upjrfdG`1PY1DIh4>7{ zE>^Jj-|ky-?h_(rD89Hbn0voB5`S8d3r|XbVa~RwW`%C)^|fW~{d3Dw@qDr`gafhZ zn>;U?;l6GE>o~!=%3+{f(+|$etU2K}I%?y$_ZYg{+JcBU6>#>BNiQ3y_+H(}%~Ohq z)oyk4$37lxg*6_$|8bLE*!auOCqizOkj?Ai_@i z%p|Jc_)_+qPj$Y(Ozmrh(u4rImZN?aDt(*xY;hU2+BEy&y{WUHp^U<)(t#5&1 z%4Md<)rPi4_f)w&4C>=x$I12kXB&52TwHq0RG3*^9luo@E(8jUyX+D1Gp1K6t3Dgd zDH=$;Zxk(_U!=y%0=pC((DS8Lp@%*Z?SRIz2mmMBHxrZ5r*1J ztU^?)ian~f#TiG0MF^PNc9lkbpJ9JOoL1R)?*+rm)}tly)#giAmLjDSd5Ussw%z(1 z;GW`w6$PJDkCGph+3VEzO2ew2_U_Jla2b^Lej`+6=#6CEEHyv#_&z@pSDzl{TG(H3 zsn|X}0Qkf+FTVCO*?XKMKjIbob$Vtmyxyk1z-j~OYN4H;QR}`!QbyiJQ#<5I%@;D~{!h7H|M+r|M%=BO@Btql&thY@MCfTLOeISf^U4OD04<>FTXGl zQw$rQhDD%C~eh%{^ zu`=VVqx9T_Z$D*(TJHDOnHB4OSuEd(%5N&)V3T?y1*R@(jzomER`ip-g;@*E+5^3> z872gYIWs{ja3M|ZZBv{Y*9;nPpQ=5l(YR!D+a4IC#rgX-skI(rvVTX9B>XF!0SPLC zYTqt(6k7@KSCvc&uCCkK#o4YXS$A%2`JIrv(383EeW*Cwtk(N%A0>8{a_E~|W<_}E zP>|ous0!6}WY5=HZiVJzM)RR>CJ1N$`Rt4sloPD?xW%-}45xI)Z*>)nnswfg;P2a5 z%9G%o1lDmZvam`T;%;f$=uc0)ynEmwfz~LcDoAG&Se((p7ZArqN4q~=zat$>f{SA; zo#R&Rr*20~Xd5Xj;pxz40@9Yye)c`_TIGBCFz?Ds7Z)k}pM8(t{uE7>GUbE)fSvEKpgoSI-`Kp%b2ZsS#T09IU_J}(tlic7Iu4&(GL>l0d^G>CU5yrI zD4%HSBJR&R?IH@|Y5>a1dG@dLe{Tt3;$^faks%p=%hat0Y%KshpQZ zaOqklV*-=h_g!G@tz(b9la+3#qEEc)-Q9bMyIp*%|614@M?so^29d)u85N@x)+n>g zhSL7hb6T?{P{GB3Gc;YSdXM)<75hiJQm6W|mvoEGRbt;jcH~^)ba=Fb{EFd|k*Anb z$mnDaRegP$n@qj*PFgUz@`A-h{(U0+exvT-qD+Ej1alU?yu9ZcX_gy2jv!SbeR(Kb z_9_`K*Jd2zQI}SQKnK}-TyGfxCUwp%gyQ3Cb?5>ecVYgP>&~4PoV#jF z9IrQW^o&gikKRRe+FNh#hW)0ef>h_Nh^bYZls+PZIMI|YQNrHoXZ6n zWBGnry24dRhWbLd5+!?XpCBPfJY6>U(v~MXZEx2p&XaOM@402NGr~zMxPzTZp|z@X zWjw#y8mj3gyks^$YOb(;ic}#@#EFl5R^@+SOL2}jd_5EnR zmBpjM(Uc<3y1q<}J^t0@Bi;PX?F|-E%BY)tsrf>9hf^oRPO~d&h1Bs?x$>N*W%}!V zc_Qom_VvqEI!h+%I6_CNwM^Phu*~S=?-#bebS>$tJNGt+8z(kai3XnuFa+_GRFNn* zF^h8tDWpdnQmo(=N6H5F5a08gc0TT_Sn6rt&i=+NR(9`t=*jNKFj+r+7gC~)_XAC$ zOuacSJ$P%yx28uU_lg(dPxKQb@3DJe1pq{Jb(KkiW!m+jD@v&-c-Ogw+OypsMa0(es)KYMev!^0alo8$uftz+f@O0#YlZTmbwkKLLd@?*27jUXHm{q$4jJpt4@$v zE}uW8T&R@tTB+xbqEtUeq%@P9$X2?2wn|eG%~s3o0(o;sM51T;K)#O9s#UE8r{x4s z*>v4wPSc9aV$?i;Jjv-m$7xR?CnNwsH(UjN97f2T)~1Rh*r za_3>`zD_~V#|YcMPN8CA1HX~60);ggMlAV{ur|gLf)Q;7Y!sGVrVuUk_cxHgkhnh+ zGv3m=e)Ylzr<1UqMd*hw&%hBFT+fL8R@0BP8Kgk?S3>y^R8lLtO~?tV9)xdAP`$e9Rj&0{Nxlg<@L@)_c_=EQfG4c2z$D9A_@&Eo7mrsLV#mP%S zHaCYfvuplgSZ41tzc@pOfma}Ht4!weJE!4uL-j`eS-aybx3wb4^xTV)Y>`-#D*L9d zD#p$8X0n0A#zu7=Gtb~DN{f0BzHVaxr^Fci;QukZpEmcWAwIaAqsqo_BqQlAohKFC zsP|mC zYoMKH_zBl$aejUMi;wwXz-^*Q9_uGM`ucnCZd~I=KTsphR@uVtF7HUivPU1l^@0_i zYB$F(kT^ly}tu>)N3vYtR zU{n4i?6+5t0(a`m9Q_UZ*PHoqnEzYh|MRD$YC*X9HC0l7eWXxcSy@>l%{<|E0txT{ zZ^(m%2Mq_&rrZxFdCpFEQ^3ni3Y+mY9>(+8XHCUK{@w=-xBxFGMc~t8zMzqeZ0hwm zC^qR&lh(BDzT5ZlaoEw;8DeYpW}G~-*->~mw32(0h`hlJET8t^7rBPqocifbyt7^cd(Kd2Z0x2JPsnf}&GuaPRsl|RbB2XOnd#vT8dkM<#&OnSC05gd9{brk z3nUa#Gwqa1_>@0@N>Vu5doBwiA^3`Hv5f9umJ*v$SF{PZ>Nv+K=R$+_(42j|Uq=^Eg#nz0@?Khf<~911?cM_|s)KQ-0s9-byQO z&(*ACPrqeRyFawjP_^4DB;+vmEIn>4Lr=t5Adl)|Mg;g4xP*$r#jO7j)4jJ~`(S~Ph7 zR}0}PgM~i3485OP?2aW+(Xg;g{VDOu9vdvzFv zX?RZPoQw_6c5(CuP!~@G@o!dmyc)z_nf!Eexg#17W~Fap5f%z?D#R+MCdET{s;_S zlmx0p29I5?3@T+SFWmiVQ8r53!?%{hvsJUJ_lDG=Et?hj7?9$@3t=ohh0b}Apc;gBp3me`cHSr*o-OKR@xQH*)|8&;p^l5XzdGn|Q9jAF zI*=JgCcCo*%MS}%tJgW(Z!y%V=~brFh&f2qFy`n`ZVA@0@ieFwFN&!2oDgb$enx%x z!TXPsP^2z!+Mb0RV?Gv`(i*4f0DX_($vV&Bgl)>>FxoW&=O35!_ig?8g~9df)KTZt z$`WMC1f^fjSype9C0`E8&Nb7Wg6u-h7WArfi9w#A=T=n=S&sVjy`5ApLEL$%E+aOV zDT;4w_iR?Meb1`Qm0Dwz0B)EamMeAg^%{2l-dD+fweKk(>;HNeKxNonrun`K>p8oE z3ErhRD%HG@0vM9FBR!ZG(QS%Hd15SP3v~NCovdg4Je$S6g4u4D)PFM223mqgMHX0O z0zB~2Nr!QZowaHTBza^y_2Z|0dfItLiZIQ(mv=wH?;TFyP>BV+RVy|c3?YoUi2P%w`NCne z(z76&2j2I-C_2{?XvX>~<`;#CSNIDl8%yt!1}u;7-bbxMh#Mdu`S*Zv)>}WqEGVwA z@m0&r)daSiaM-M-YOoW0KK$wfKcl0EG6v`euB00GCajp-cp`Qa^{3qrbJ=#;Zy-DO z0KQjB5FbN=2W+JR_`ZIk`#~miKbI`>&mf&?hMld zZfoiunbVBd%Y#e~@brr54ORAQdcbdqQ4b8S%y%kB25{W|(^F3;gz7wt?oky*IC~6C zEr}N$1ihyVF+i1lImhR?skuvQEQV~ANKqo`9H>_?UZ`qRJ@V*-ftz9@Wjg$Pg%#I) zOjcm~A<6TG^Jr_b;z++ePy2n;I5C1ahq;a2HgfGD*LJ&6iN|Q^ur{$mnpC^ReFph# znRvdwY?XYw=M!}&n;O26S-;x-7#(o9gIwn+4jGScw!>PEsoo3PZrjZ@C;U5YRQj+z z@VBEZdgMojbyULcv+#%LdVN%jF*G>VaqA~pR7;Ti)BB-25%r+Em9cGXh*R( z+nMjmbwLf)>Db$xau@Wf97tt{N=;fTDtLELHJ&Ogk}0q=*Un0>E3eRJJ}bSJGMjCt)v93HQyghI4{Mc z%==lt3-m>Pt{- zC?_9`=m*DLbl<8yY!O0i2gj{uA%h|S>nnCT7#ZV5S&n&EfgxM-i5!CKWf9I(B^a(i zG6ZDnrv^}ivE7g{_r51=C7sQ%BfMh0sB;!PV<+Fymgm`tb??1HgWQx5(V{k*PuA&iHWILfdq&$3{kESut*ud(u)Zv%>_AO?x zXFYMeP`yD(p8E}{@|7D$16A4ejq!5XOYMW80|1%M(Q&UQnZ;O1<_6~?QZ0>atEheu zt1HjseLtKo#JusnfzET}CjmF^0g_IOmB()E@_4zG=JQWzeNdVq%PT}$9ofJ@-A#d# zImGO|BBlC5b0sI@-H+g&k&7Z3$@KWly4Nhf7C%?LG%NQi5>WrKZ|D*I)Il^!)+X~t zKEt1${m0G!@yuRssH=T>0|LjHoi%Y-q8Dxw3-zoj?lzw#r|BJ22p7Os_`cc#U z|2%3)h|Gk^3f>O%BBDXYBEPa0FO(~QSG$w3iH@7nP@vnG3|cJKpu&FrqEb)u)-Q{6 zBl}nNr0!%nF)TI!{5rq_4=Z6C(Cp?nuAq^rbf01gv#1#FXx0eL?@#qx|%^ ziYcI^9DJK?hSE%N2UO*rm)dCN9=}|GnmwSb@avc1XHEb;LcN=5Y`;|tWZ;9+G0R6O z9o0{KCU*MNNC4DtYL^D`w5o5i={EYjsv*pJ_Dn@@;>HqDqxY?k$tEWXcM;Y=)SWQhW z&bozg8#ET1MX>HErY6+w#&3Nr?j*Hoy9Kp-6*I8{f9n{{Edl);>x!nCD0~-v0yGW# z015MQZz4ynxMDfke-%S3fhZogIpS%0yK>^as68RQrnk#| zDdOg(gUZC=&LY3A@P3?QQZ(u+e*e<|pL1TPXe~jcv7U5zd*5gMSzFjzNpL`eFc@$W z0^qMdHDajK1J&ApD>VN!#R6xD0}$BElSooWRnAep!K_ghFh4ET8mVDP=nmWS1$|cT zNG7$=O!d@WM?luHRL+MkkCmFGj+_3@=L;uQfd#Tz)Zo}7S5a_irP_!nqON9IP1jlP zc5}CW2E(Nj71rDP`JS~DR8U`w=n|RJ(-PA`29J~R=@#H)7+>>ce#;K#sQ{@a=rV>) z&+dgu%Gbo0UlVGtC@TcFb6eAx9!ruba$jvG&>;cTQZQg2E##C3xgWPw0iwSdw08+X zBO%X}d+Zm4z)y~Qy-gDE4ccx*IP_#*faK%{{ptvN;WuP1CS7s79QyGKol&hyDq0ae zcMd_H!Z1f=^d zzqPJ23VVA*`YeeTHnwV|jbVxTD0{7_X`1eEwhC)#!1H#8bRVA34F#yP5zVGAmZMc& zc3rDwxbC17>iYGME`;Vd{<44dlhgTJ2h7)XKNv*;AzEkvc=_9r?$C|BmHzan=WW`3 z4uCMAVyo^%uP<42rJ+pAVU%WV-}d$?=>6kGX}dh*w3-sYytnto30yK`S5TB>J+fBd zm)0|22{DL=uvqtN*Ox~M^=po1{nd?wF<4&Df@NX=ShT9zqA$`JC5}rE{;r((i6X!ShF0Zj$Ppb#V3VV#y zM9}i;5iks6haoj%CDrs0yif|j)K@d(vucx2i3bJ5JB;1l+8oZ+AZXVFSJpcMUa_DL zy1<2?$y{?X_*0wU7r{li8={sM^9u=w1rz#Ds)9CL;y9Eqt-b zGvD5j2T8J2QiCCqzN7WxUJRS|jk0kTD3L>?`Pc`F_|;!^CXrK8QVWo$sLVwUyfXD~ z0H#+2WGR@B@hiJYDWU@AzKCE2Qp>SiUMIfuRG8CZjFUHhcpEI;f<~Zu9rTI<0Vv`{ zAP(!727iy-yQ=`m$@i6cMoNunp}As?KuzQXa1nctoj-HgTka_*DgbB71MIm}?t|Ew z?+IVK$!)1w1AGyUSS(b{>gfBo?M8AiKn!5d%l+(M>JN}y!s{y}46qySX)`Nq056UT zy(`S}fp@cF&W~M~g;1l`W&f+%Ce&)wnlt2YtwWc&V`^q z+v?9+rz-RKSzOirkjC6=V#~MnXYegF;_ov28@L3T&+qd!P5~gLS>R!h-0k_*s&W%3 zWg5(z`)qtDIyWHoQoW7k91d_~L`%BFD!iR8kwo_1zGBUG3$b;_?er$#8L@{)ppQIx zQ^4stX#KGC)q9>fee)sM*;KgnJDH)G6{Obf{C797kIEZ>-t7^gP4_5$h*|*($9d?0`5q<#Dp{vRgmD_P`Gu0Z$#+^)P+@%kwKg^#uR<3FIz7 z+2Opu2}Y?n#bw-1e2Skk94eNI%homqhZr?va-I)q-yL0fv z>E3EtQlt+?4$VK=kGUX73S5b`j5rzL!T>DH0W;|uTZAH)2qrJJS^Rs=X!FGP=CQD- z`coR^JWaKb%puT%=@HoN+EY0>*tqgF{kL!!S3JPH(#9JSs98+kL2wr>f*Y6V2j4q* z3v@@L_#bY61b=FhC$Dnx50&6-?cr2si*jZWi&oXgay@wO*=g?xXcRIIDjWVzO6aBn zDWQ9AGYgf0=8ok=1;$z;(66D)BV?b&T9o-hejLf7MZ{s$_0}7cFN1;$*o9xhJy)o3 zA%S|{HNYkD^87LW*$96=&i|+tw^mUZa38UM*Z`gcC6oaBu%rU8Djif@70Ot!I-P8k z&p}EgsD-*cPkTXJi94fC<3K6t_fD{&gx+_zDdO@t27lxNAg(TT@oy?<03nG3K#L{t zUD$1>olYlL&WGa>QQ z#Ty}yEq5!b8GtGUlV|3I6UZt>L()Y__Mo~kBlW4gOg)~CfK-3hb1kBwhIw-0Am_}z zyu$JpC_!1?-!)Utu-yNhaxDbXGLwWT-YVcl)dt~q8E9{YB+H-m(=PVJ6WgyzV8q~M zVfgs2wY{VI1DxnJ`!Vc&AEebVFBIKd8)mJ=TLa+>K8VqSWD-A{B$Cs1%TdeU_h)BW>iDi?2cAU9#6vsD7d|D)lfW zs9uNzO24XemC`j&FOk~GL54sY=LArpC~)*0vQI!3rVn7sJA*t)lm$p)NzcgGS*`P1 zA=8b8A}o&IOZeSoHz0#vd65Zv@P?$L>!Zaf`mI4~YxFtVUevJ@f!tF!AtVi@9<*xJ zY~|cp(0UKh58@T0F!-eS8!3H28PclTFLYO%plyO1Se~qQ9NLEL5t2sb*yCENdl6_m z-2(OiTtP(_zd=)c2;d@~-7XIOnFg;ufY&u+GsXX#-Tx=k6(j(g+`m&pEq4{=4T;So z0iZxqdt(Efx(VoM;LuuRUIr%vKhb-ku!=pS^`rco5I*+YF$;{Vy6M zBovmE2AH?(6-ILp8k+Aw#n1{WoBbU9DM+=BI6a1F9)sNU=et*^y=>Z*b3kHn`gE}v z5?p`zATsv~N9OIk_D`++U+vI&P znhLVy3~32u7x#Kk0kD^}s;F(ojlcL4shw~InHv-;pR?mpc@se90a(DQNkR4=-t@`T zVX_At=G?m+p`z^@Cc}68J+~DZFdkhd?HZmfL3`xS{zcZwxDCL`V0Z*)a40@-7k`LM z0rv3Tp6m?B93l1;*gg|8WF~-PVF%zn$S$(sK_CJYDALAJ{PQ6q$(CB%UwmwS13AmN z0QrK1Rd+zeMGPp=LlT!94#}4ZMm=#cr9q#+;z0$K-fWZaJM(53_!8fo65^=990G;Q z;U=kcEEltCJ>RdCR!Ctb+z*)k6SdoOIejSNB-Rh1Sg}R|ZK);LV=o1m{t);JfhPk% zO)7>ha13xIfx(mZvOM_7VK7Ip07raj!S9uEawyQ2p1!+UXmq6pz;j5eE?%@?nwA0r z$ToU$Lc5i(FTDWiK?ma3`AZ~n1%kg36R*=>^g30*#%p8>@DldLfQTTlv(RVp zc3&T(%uCq0XX}qVmRq>SJ#qbU!NmTs4ml~G9etZ2t!x4bNGX918)MB)zBr6EtXFL0 zM?53`T+kNNd7NLqDrChnOew+03{7LE3b` zzl&A~Q2=rFLu%j-0cFqdD3R|c@h|cMKd_fMCd62aOy0fx5p}cv3<1%=%KjIy1nxi? z3K$~x(SsR~Ed!t^>~VH7-3q22>UrW1>)YL(`a}tu0cs}$DzwgOq2EblT&XWMl(|#O z%xEa>DB0}2p@$Jg_`Yi#z zqW<`Xx%oe71Cg8x>0srgfK}l2o8FYny#ZBbkbHF;h{}xOc7Y!JCWHwtUL!KdNqHeG ziego>EvD%(YPg*)1iuX#k6+f3Vjai_P0!NfBd7fAfuy-TGf?86mqHF=UfnblVH1m? zj+5%l&w=pL=vs*6b1;cSFPx`5P2&^eh8=J`K8@gls38dOuY-Ek*)a~)aSEC=0_!J-l@BT9)a6rz-fu|L=uPgAtI>S#r!)+il=hEJSKR z#1I28%$jqRW6rMTp=#s+D6j#(9xBB73M_z2_ncHQD(Ad~q8Y^AzNHF!TMyr`0^@j* zj`e&( zK2!y2IZobXshD{QL6~(wll^9r>j30Qc0gnm>JBc%osc+;=&HG{021N;g@__;sasxw zsM_ElL2v|Yo-DX1o0P9vwUeMw)Ngok9-_oYK<>yM@>Tu~gJHlJu`Km_{{BXWUjqmn zI=aPR(k=fpAH#Lf<^!;R-?AQlpjzW(9dMJ45)4VbKTHKW#IOng&Geu;7NYV2;=*s| z{f&a-sRB9xt+&IqyoDv60;o_3*pg--K4f>{eD;+Zk~;!LsC^3`2D-Va*BN~JEU=TM znh7EjLF#2}TL{}w@jNI_YzF5Zji{r4l>R#bCLC&o@Y2iN$iVa})Nh4cBG0*n&=@@= z8`I5wk>+{R4e_RF#6h_eXu_m;o*~|$RxG&I0ChMUG!g(THO{8v_V!-C?9zDZ!EYR? z4J0v+YJQC3gZHQ`QmUwpS*?g#zZHxh213+HESClQki2lxP1Mj6=hLHYHefJLz*jN2 zK7y2Y&jTRmRxF?&Hvzq%-$Ish)es1qT(dfeee`r^z8y*py3}6xQRcb&URFqHqi9%G z8eRp1HQIoCw!2sXDt<8=mT9WX6>C5Mx?Z!}vn_PCdp25)btgN^%zDP`_0+>=nM>zC zy~e{qBNn6*6IJ|@luUtt^AmR9inDKT(2F|Py0#~LA3DBhAx{s}{&i3upF&foR6#tHfE9{V z*Y^F9XOM#PPZ2YVD(O+)>UwEJWLN`0aM(~GFqB?yHp~Jvx$o|_P>ysw?&GQoViD8esO;0or?(8u8{Q=Io!A%s@d2(#S=LHTPX$yaT8>cDm;v5=IhI zy%09MPESw&R?r>RL~K>_jyGr@nwbN+VP0Ur*`J_w=94#s(XA23ORa#vh_#iu{7(z~ z6vDi+ZY70j4vrXSGtqgaN=6y^xhUtVE3IA)MM(|~4OPVOm2iK19%X^P!0mXaVkIq> zeR2VxMKgL#>Hu`0yX13(PQPJ6Bu(Z*#J`i1ZLH_x=XcD6a?@U3rq-G-!fT`HzXzt` zaNCp$+&SXy{+R26rU#i+3n-w##j~1`k_;*hULk{y@Y{XG#=Vb%^guNBBnDsh@TQ~w ztB(mIE-zC@dAgd4;yru{pa%#g{!&pDU(>=#qrN()rqfQ`<=gVv8lo9 z0yN>AIUoM-&6NyI6u)_fVUHLKni~+~YPUYZwq_nCqXLqn4Yh$Xjkl8g4CtN*0Fz{c zCRd<@W{L`C&i!`|@|jig+?@UV5AA+sUmmPkk3F&I@# z7S5BRIjZP);x~Gku{G}K4Bv{gi>kX42SJ2P^h#Y zj_#G`2m?-h7IZd)fh!va=~;j$>A_Jgx6}e{xO;^l#fSqk8G125q4{W0+^z(2WJ0nG zq>U>w0dr&+@`#qEA$a6x89E#PaZRbr3~J{A>od5*CiX&@5VCq`###VONI~=C?8)5b z6(EK|Bj{3&m7uq3*l39j-gx%UYy54hiYDhpZSY)NrSgg{3+#OnfqXTmA3~`5pI=>8 z)4z&MQSc2K(hdYuCV~)p?_z5q_AowZgWmoGWis&{V;j!wUk%v*z0mcHILIQG>SFBC z@Sp*@n$w+5HRHnp1=(h>uUHU<&!Z5thS=GVfU)=h5?*!y(Mz^3OH`%+tFdmzQ+Wv9 zBcKPUW>%Vxairt=vBD3F1kH9)JUMC=dB>I-hWG|>=_%kX2Wm@`KqLdr<|t+>Gn>WT zM?tm0fjZu&!=7*z0nk#1?r0(uK0SHYbl@!legZC(dF^apk&OQGzntTBiV(jSyK_%; z!(RzE0g6nOwh_d2ytar;YUuqTe>C@jwghVKOBGK1AtU+({V_V>iW*0hMQ&*&N!z;fI#t=$HSZtq@1!_Si&5ApKnpYH6WC{~*#&+6n zCg4D`^#rUC74Q4Ifo6X-3S@-fdk~vLbbA5$r(9>)$37vs~UF?6p zG~}gMFhKmzOE*`NdkWmG4>Z_8e8(!v^Z5GlaUr0u3;;xU(GZFAC`h&z1d=~SEI~mq zKsEu;=Fy6*ClOtun+>P=$eq#}?0@GKVri2eS@us%h|X-GKtqyXP!qnDU%%!LnR#dm znHCt#Ne;j|cIthdk+kttOKawr?nN=Xg#i5I3lVE9)%8KDLa7u&Q*i*j}y zN|Uq4ONnQ##M9e@RKWt+fD1Vax?y#LLhc=E=$yhE&`}30iB4BMKX+*+Dd>f5L$m*( zi3GrQWSR3H{<|NH0kFnl9-aAj)`_cL_}ilAE4u4#I$mIG&WJfgQd!XC z3k90Z@d@)&LuUp#Ik}MA1}9(_B#+t5!7y$LNDsXE4(*{d+jHb+JkU!T0F@~NAS*xb zQux2duj_3rAV52ir=UvU9l_S}pkN~aR!WOXrIe(ilp>l*qGVTgC8SW1HdLow_B~lrQMM3K zWNWcYn?0dOp$G{je%F1X%*^{^{&_$1nR)A+^Zh>0y++=48T8s5{A z_Ov(#n(ox}S?OQ%4SGcZ^=XwX&Kg!k$aEh6RNiuK?CFVJrp%CUFK(N?= zrH(jv-(P;Kf&ydv*SbfeTCteb`4b-cU|ww zgN}t7hKT%rBC6$WcEDm>k!9xToL|OZYg=!KaW>ZQq{|L_oF7#k4QjP7EQ&r)4ac<& z&i|!c2vcBGyigB)l~_{5289^>X}Ol9#1>$KG)LVz8Pqx~u_Y-`SdKWDxx0!{M~Nkt zK+x%?QPVV{N9gu|7XYVQRoiQ&15q%)22lT%h5<%yz&d z|HiA^K95C~9{v12irp%g?dX>e;WC!-EvH9O_D2=(h~FcjprG*Py1(TGK$dS)-0I%H ztJ_!#vU-8%UYKCG^K~>1A7*;f@gCE-Im}PXKr3KG9dXNHJRY%3A+1v=S!8PZSeGKX zF@hDUL7#@-Ey7iNp(WBF;>%N?G+gB;qcIuvgZH88ij@jAkWo4zI*T?*(OkKo>;WzA zDFQOVd1z2$#!eL#p!&JsR+QN~zN7E2w7$69yFB^e$7%S`O^a?y4)^4OpL49TOn7eY z?cj4KxbXef70XoJIgAv-6d~wGy52mPD@9pB`u|YPk16{A(%%a|>a_Fl*=P zyfM?og`ruEdnQpiY;`FVk0l}CBJh9woI~lh**_# z)_I%@INsaMS*QBU2i|$pNh%hK!JmF^ubm?O(+AilliGyTN>I;G=3Hw+b z9w;cq!gm{n!w{99;Zq~uui1I*tw`+d;)u=L^MD`fHtKS6aT$I2Q0`}G9s2uJ)IBns zR7%SqN+M-oNwl8-pIPU@9IyU;+)O@}sgUKX)!qTa_IAt*b8zQm%SX3|#WFybI-BDH zJhJ`#{)$ZWgXUm|2{}uc(0wnTzxm?$_IFQQ9YvBC9IV`*9l+a#)Ai_h@4Mq!Fk6}i zS|&0!#w9%7vZRIe;)EVRsp-ARkKMmxQJcuo%J+Z)^JZ~8ru z2D&2uz6;p;x54}WbzEaZ5x!okJ`YlBU?XkqE~p=)FzQ^Cv=@4H6;;)VSRAxuMHW@4 zd1{8h^iU;v7G7*BjZrcd!XdTS1?;gOegksg#?^8c4qpfAGFInWh-e*Ilq&OFRz!!X z8<&BOaVt|dwAze|@{g457biLjR0~+xW+zdws6#HMfP0*!&z#eqZ4(fM{y`zK7QAUB}jD5RAaT?C_@= z%BgRPw;DX|5sp;3wxN*g@>=_&)St7&+*H9s#+36Pz@kAPx!R_Yhq#s!8=B?c5C4k( zgPF(w2@Gd8(1|y&FL4A$R&?F&!DzwtDk>^``yWkE*%l@uy<*#Nzs~R)8&9qUk8e!` z|0gtYkKl~tX%mjxYY!>mJ?3tuaG1l(gjg^OWyAE$%uISip@~uGW*?z0op~eZ=x%cW z?*9dNGe3VKQDpj6f$IvRD-YK?8%K9ubrezM-+J8xxk1RERV+ot7hZrX16e;zrg%k8 z!tac!2L!^%BY&%s)Ur^y>K97P8@A1xE)?upc~-$8aw3DIzt_(jp~(r2zJr>P4`;)2b-79|UFhfIuzd^v4CtmULS}9@+X%>TLa(!>pL%15gfiA#- z)HN-~I`3VC@s_t$!nR>PvdoI^ox~och#JP8(rA|23*!H{!sQb4V+kZ+#Z3Oo?EOVG z&hV%m4bMZvg%g5<`GK@dLKuTF{HPlqY7>X~EPgkR1s?78RE^9;Wk5;@P1kF#YgZ!+ zxUm2awulQEz_H&T^j~=M=FLXV^DmMQLg&_%t8~nxVfhVfQ|*Yh{}r%)CHmk-&IKNk z$+mmn_RV<;DEKf`YkhBD?M=6X(u<~nzJKx8rv_Mt;B+K&_nrXZrn1H{ZzI5rQzj-p zX;*PX@!6{RE`wX}|CQP8Hp#eG-dU9r7Qv7o6(aSeY;IGVKO`5{^#u+O9z2NJ|2qW{ zZ+2Xa_$fFql?c|$4mDR6Ef_0N=Z3(wXimd>Eo8a>P&#)n39bn!73DPsr?wDE>9 zGbOh%b^R0=u&QljfLXHW`En=yG0&uG)c>q^@~7zjH;=krk2^jELJ4OQqksnuP|zO^ z>ErLCBBf6%@qs8?8h|NkGVB1(hHgMfum%+E_oCTT0u7A`4?(&ENVJM;k^(k&<&vXIw#^L>|8d#N`M!^JZt zc>&@)Sy|Q=#}#FezLpgJgvU?o0)9!N+xRS$waDUQcnMXhzqIEKx(4Tvn#In0B5x*M zK%cf$tt_C&{LpZC3Uj@TdqB%6p~auzHnYC7`BnThKESZ87~LXjhq`+I`Q&M4oSZ)| zumdK11Q4j# z_s;hAR^gUSL*w+O+ThzsI@8a2HzwygPZgWL!G&+Cd}rb9XaH5&1a443CYQULw}-iC zCuHVLL{H!#p0EC55+yIP{B-9_(ymAVhxv#mh!7q^&m6u?AE-L{FpwLZiM1H{xCItQ zJ+3rDV^JZ{FJxBa)c+7a!uS}4vm*Jv?ey_qM>jx=tIk7?q?I@*r&7Hr)y$6tCj1D+ zu~>Et%@L3`&iwWCM$!OmvOn$wL8lJZ>zavBS!dbeNNE^=V=x> z7FtF`Rd;1BImVjggM3$tLR?fUg`r5}l8uta&!Ny!1!uQ6dZ4IRlZ20GyQ9lWoSo_yJ{rhaNQVRkI=hqBk3?Lk+$Qk&Z z=1wwzFRr_NL}`f&Z}JE+Yz9mx%P#U%PrZkhVY9m~oC`??unfIQi&Ojjp<@ikPeSIg z3D34$J7j4|133z+URFgSySQ?%zQC)KESAwtnwm*6$s!*4SmBL?I1*S;!A>@AR{`4n z2Qpce2Vq)vbGT3E^3 z_)$nC$|v=9Uk~xGBw11Sy;_nD7X(RtyL`_6|F!MxzbKPraPK)|M_-RMX7jL=Cf~oW zu`umjjGEf(N3lWxot0f9ot4h&AhI z+{FL(^St3C>C+e1+%0xy8nMyO1-lHaY3|p~mRY#pTk6w6wyq%8 z)b>B$75H(}t*c*9LaxVvE$24s#;SkD;Wni|-|!j16VJzT7a)TJi9 z75v5xhDXngB8;g|S+&oQP>TPM6Veu=6}cmok|)NJ^ngh4v3=tpDCCwOZ-0l6?)g|I zjzlJg>LyZ+M4dm#4eMhC=n#w`Gkq4Wc7s$>V%hgZFu40JWjN9)LmDmew{vG=+LUWf z{5JMHP5w6Jk(`0(%91IkScOQ3Lj;kpC0X~q*tO6&Eu@DX~j6-T5BEz zX}xQ)%D>f&ImjSuR=B& zfGP_Pd<#eP3Sag+>-l6{=iCfUGZ~E^u5*{$fve+xsa~hEI7&;5jE9kX(aN{$80in4 z&`)F>;(9O8`AVefW*q}pQ)nQz{yhft>$jDtdngP&A;pwL_310;Z?>?{zz})@ z%m$k7e9Q7^fLJbPn$Zu<%)=Wz3n18vsG`s)I{ZO9c-?Y7#7at zp9PfT?L!gmhj-Ze5tXbv*xkfSg1s52dcT+6N&Vrsprg(&v9=?~w%LJPiP8S}SHyd6 z38z{8&yB^4VAp+dSZGmsDiVT5mY&!8~HWsYz~>D&<^qyPdfc!zJcSiR=sZ8cpKz4Wpl zk!oQ0hp9rqci0*u{ppMML6%Gu>_oI1D|vD(mfvK>q+mWapy1bV30rAM1u2e-p=Yp) z2{3IVqiLmMZJxW(Xa?ASDR<{TS&NJ3`{bU^nUX{l$dvp@2i6pE1CSKp;U@z} zQ(c`|*HuIf?+ZOkVDRCJ06aULNC3KJbwfxP;E3Hv<_*pM$jFXI4>sZ8eLkznQ>2gC zU4OYHalLfc{c&#~sQfE&yb&u%gHsWhQBN_21_qIe=X)O!3~WSzc57H#iWW)TYPj3h zM*L6Jnwsu#toEyvfZ_ke6{YAeW`Hlu|M`o=nWW&u^bRR}-0cEOic!jv_Uwmjz+f15 zBrJ+FF-?Vjoz<-U9~)g9@((8LdN#+ysKGAhvSRKO3gzl1OjL9Oa3amCCWHzcKS!Bq zKQ;--{wLx!(d$Gazm7tMwYWc-0_7D*v1oZ?q0!VQG4q6#QOg!A3*VdCp}E;lbRMZg z=#3O^x&&a21}eyJ9S0M&bN;ZPY?%k4Z1NUQ6!dC<-RIctN=FN=Kr>9n5%cS*46wjhQwh$$SX8G<8-fgz?4%``6|t3vrA!op5~ zRb_!c6V0wPEXTSL$eXUVN1OS6CXHxpfx~*#6DbJY-<;vq{~7+(Wm)AJjnx(Gr+2l< zIT!(ZKNS12PlBYbVNzyzcVi>izm0Oz$R9PH9LPSD4I_l44D}(bt+G?iNWI~AW zDJ+@?P9>qD{$D$qSTql8RGcwG6*4S7YJLIWjiQRRQW6(wvB@lXTlz8kaBDMYe8}lV z1xJ#_#)K(!lxlf4G&+ z@@2?zn@xgK^|s++$(RY~S^x5Sq`rWe-rEsF7inX!@JIA(n%95Z(zZRlUp-fLfJqH2 z^;gI~Pre>%$&$PRpkqHOO_SvOkMLWbZXG!c!fk$=dJ)C?vu%^_q5{e5aZ7{n3RO_b zp}cl_eaP+A+SGF{%i5{Y*fV&U)Tx=%8BZ!fm&9^@CDV*j*gBrT;YtK$Wq(mcoGTHau4{d0b)#^ zH+`aw!`PgO>j8tl{xT_^kF6J6!+HpK;?{NpkaL0RW&mFVNg<+)&WpAiVJ0982J==* zUFlO%oLzLdu^>=B1ci8jq8iH+cu`iAKWN zsDdKM20aH6tcOV%lOJ%v>mJrt)ZTuv#WCbXz%cSi|2cHwiYnDa7zCt?TU0zE7{$Jq zCW(kH9t5L+0tG4R&YA(kc*eGS3By@%6wJ#;8nGYi3XZMQ|dzew9XD%(G8G)945-RZ`KE-&lzoioQt{10->q z{pQ>uk%LF6nXY_i87-&)K`5F&H^g0SXg8uZHGE=EWoe2|F-FbefuC?Sm&e~=B&EDO z!o^Aic_PrEjTa0&pxOfm1|>rDsd;;89>0l_ z5eQH0AK%j;H~eLA(THkNSj*Q!L-75r;|ZB=E@I+=aQZb{wWRkQ+s)mG+Mx$CnJ#Ku zB<3}i##|n*zzeISlA*I#!=XGK{zcDli=y_tf)siOf@VK>f>Sw3sfH}8bTK|bb1m5b z6V?0-PyIgT4W!Vn5EsbaJNQv`IG!4Mb$8vjukHznwZn5Hn_EfJ-6j?4`&_;RAE?!T zL{;VO#Fd@HUW44~hI#Ymg+FdTC*89h<#?uw+>A+Q&YT%8<1q7RLZj`2hIc>%0OqUk zQn-amQnj=i_!o_Mk)_|yBO>#5{KnqGSrEGcqXEnyl_0-zPl+%KbH=>05!#1grIG4( zBR?(|>Yb_4Fx3T8W1Rn!o_sg1%S0<2_unQ-zpKuj=vC1(=JfVcFw(l8rtDF*TkF5Z zcw()`CJ_e|l3CELuy$k&R}!g@r8XdYtwyfaF<`x{rEGPcN(y?%+tz&zkg%T9Ft)b8 z^lekC!6f7bvd(WtG^S{(rc;M*ZWhhQ(44sPzRQ;)h7^DPgw)^nv5|8gaMICD&#s+g zNK`Ll-8B9u?1`{8ybH1mFLY`vzDpKr{~2e_B=t@E2F^MYi!&}Q%VxZ?o(9hY+ zM7fbk@845U$%Qz0Vuy2Wlk{iVeOgDv>Mg>zWqI{NmP&6`?)-n&;IJ;y0y&(Hyb0CU z(sc}5-()@mnY0Zl=Fq5~mU}cXM^Y^`9zOv#4s}H)tp1jJocspqL}q1@wc1~#CZ-M_ z5MspEn4sYTNm&XN%=!l9E7#RPG*pN>D1@w57)gq;He9T46~@V+=}i)TkqG55SZ^`8 zySxAqQ$Ay#V4n;3mQ}NnnkEA#wh%b;U4#W$v5K`H(fr4gqM8bSpHLbKlS#*2BZ~g; zY~G(c>d7qo&nn?fR0#WtnQlPq{_E$BhvF5zB8bmNlx+=Q#UeeazMX5FbKs0-wiA!^>jtlW^y`C~*)LoXOq z@qX%*UG~fZV@xr`e&Z)=;wt7p?(Tg&0jmwQ=6eB~Yal>Ufi#Zv}>S1pN1yW8Jo zBWl0F>&aPW^awRcEzQu9qec!N_wg4P(kG3nwf@k6bJ<}$NAaqH8DKu4z930p7fz|d z<0`mLEC7F1r!-J^7+P~u!%FURE(v ztx{vylX4FqS#IxSIg->u8}N7Tc>Ul^=-Qi*nUI)=Mn(o&WSnsSO$4;j5+I6bpyJ2V zg?Xz&+A~VEsHg)QBK#Fphn6~Y`Jm_8yZ^AtOa=j5=s=C_KeIM^!QZQ2lR`h&a1#fq zglWelsTnbFA?z)uiLse25^ueL0?-Vlki@(p6$dqa2-WR@%FT?xHHTQWd0_TG5frRt znMdUVhRr6ClObW>337sg)=OZ#x~ii{ZN`dWQk{ktY7~vC@0_t;fcR%&gPOO^e6q}- zaR)GgC98e__vruICepwiInw3uBnL4D?y8Xh5?3xg*d}jM_jn4 z&n%I|=&-1%*kBX|aVSqM81A60um;J5*(-~HA?w0-4P+i_9n}Pd$jod$>&=q*X;kA3 zqwyS=cS~X1?1X!ZE2+rf@v|vV1KB`qmiS&6tAu7v8Hj!A%b6h;7cacD2?Bl05UTp? zx7|}~8^?j2Times`)in_=k^3C;ca`f=BI>L0A2_}Z@3IcW;Bl{_l7j|t3LYXE5rMN z-VIUMG=*Q_9u9)F>&{(g`?(G3hk)Cdt}gBX=7_I*`_{roLuI}&(qm~PEsmMOrH`q( z4*)L6oH@?b$cbIXKT_P!}Oh7#l%@WDZOz*~ztM>sZ7e(8dxwwjj0 zx^?U74~1R5dUX{v-*bjd+(>u=f0v3odoOo1AfG+v%hbl# z{2|9;<$-Q~l0i>dbI_dP2dXnw9aTh-T1awSW_^Dz=YHUl^-!{&unUYc8vCD>=%z8` z?|8*Uqgy=7NQ(1v>VLW2bI3K9_6_yGhc}lew*vzNEK0S_BUz=0i(u{PLE<+G-kYyR_VFBFs1qHtEUZH_eeaYL3{rsGm+HK%<(S==i(c_5QWE zUoP0n7?M~?)4$~2yb6XrR{^37(}ZAP@Tq+C)#lAXg^Rk~R+1j~Lx}YSMv~L27Oz$H~o9u4@nkPIDqz05+O#hBwq%0t+GOFz-(M0 z;WlwG{$ACYHrz-nv}G9fG+WtbCqiWhAM})3TaV<-KKBTdzybXnKOSgs1Q($S)_?4Q zf@m|8mn&Szw*Z8r>T=q2JIoymmL!7z#<5AZU&yDMT(FZH;aj)#MXtaew{-(WA~T)U z4MW(Meb14sGuylsaP^LX7uMzg9u8L^C6w<|W$;$;>= zCweTiQG!m$rLbRtLN}-89y?|wCelhwRL-*U^0|jbSvp==XXt-ZMua(Kso@Dml2H4M?N@&ML755$R^l4z;!KeKkuIKHi*5C$ zw-d;sn|OZhM03A}ZJp4`hj?rqQc9|$06=5$JiRlQ+o9Ewqn(`q)fZ^YZkXwNzei&1XwGEx+2WkW780-ExIWRGz&7Mdbw2NRXTcX&gOqAdA|Ndd-z^PMLA>{i^OWe_iS5QYrJ z2n6zLc0i?F*gaC-G#RGptHw(Ad@94J?HiIsFG=qa9Y(;ABa1Vl`?=CzgTGPOdr~}fU!jg+KygPlhPC8(G7Mz&>qBG7wh4uP z;0n3t&LIF}e&Kvb3&NBZa3xtjJ|sF-^VhZFYa;J|8X-Y6ygrN){{q}ELPW^1kOimI zzXC671mljseT+GiCZynr6ecNbUnJ&yYd ze@rjGL!WBy8)tD06tCmM%2*m+Vz+3DoD4-i06&*d>O!K-l%q{Oy2!g74vcKo3pT!k4vxr@fSjaL2 zr<;Q$B~YJx=C#<9Up}$@L=dsIj-!6kF8T2jQ?Z4I>-t%doH=oxF+R}sf>-COhj*?mh-i7Ckg z1YX0ukp*O@Lr$~6qo_1vDPA;*abevF+(AdQ zxYvhdDVRN^cQN>;6&)#`d_+KQkMTW^aqC^d*P74H`k71Gbo&cv_nx_qtS+^f)usNx z6feM~WoVr>vj=(t-&x&S#+0H-ZeAU>h`f ziWbE*{6>>}FgCvpDbKoL4oCpwjJI`#iQcmx8Z0kN=!CFbQu=ERX2e`&!1AnDkLyR^ z(FP)IVXZ0g8`WW+cgPC^h7P8^S2h&N4+TYq-KNu6aWiricOUwSYv_iFkn>s{9&$=f zUfyBL%t2>={6;p9>c!CY)!zluO@q+kS9-FK_s9WZ$2F53+TbI&kpo(4n=eP>Z+^z% z`Z3{*l_yZCzZ|=9b3Z8?6u z9@~bfh?ty9&>)m&LlKb zwN~7OU!tUgEXY|~88ATNoTMTA{{o57{&NFy%N38hs@Qpd)GQ|wj5gh7?T!XHJE%%W zm+B*<%6|xZuQN%9ApcrdyOcOpUcCb<0VpP@NgZ0gs=N-hiiVqWSk#MEFc*CTYt!7- z-$P_X7J3b8(Kc?XAr=)=Lj}@Vlc%3MkN9;>OjhbJ(r=RVb{-U#89^lmjFh%MTvuMeqw=kD_8n z=Qrrfc`4ZN*%YZfL#e-cLKSb(`E`r|F90+}o%;iS|~N02sD4 zvYfQ(|NA%`hC*CJ@Alu-OR}p0sTd!tA=xN+)~M;`RRh;vL70`{F-IrbXIL8%8GXTL zu}*!;CEBY)`c~`T;n zQBCBtTnpvzPwf}I6ATbvgq=7kIA|YP7HDAiyjqxb&7@_~bPva_?W!3XfpZH&xA$2% za`W|&5zQ!Z3X-cr+@ften+Mk_;}srpXJwB|$fY@sp{e8Cp=} zFG6-OA0z4lX?+s(5j*v4sa(e*XO+L>Dk#9%n8eEw_g~;1g`cy-w50@nyO7_H*^QkvdUntC+3|@aN}-vCD?q|D`8$`*^baUjE|f#REb*?-Ou;21O>Mt zz{lY_6*Uvx^95>Ae^Qe4ki8Z88zSroRiv2BqUK*nLj}GAB`WE{&9m~T-TDMo8DY@^ z*>TA~3!H!d!*gUJ-ymas)7AACjYMbtZlY5MtZNEt{eqv06x=qMDiWQ!z|)f`i_3Ox z@rjeHF7}KK;>)an`hVAOw5$3G=7Wet!=_hZwf<2nlAEKvML*)t9a|3Vp2|3(P7@udTpyOTx!KMi*S zN-A7o5Wo38j2vdLESZM#`(UP!hgQs;m7ST+Go@COi=xtdmM*0--1ujv%9+cg+jOke z(clqe0dHty3B`VZj8^)u(FkE^pM}`@~DX&C0I6c+2># zO5N47$_uXDl{Gd~ezqg|s`F&szc?&(7dMuqnx*EdZd6&Q;HdJVuV2Z3Uaf2tHsYhK| z|7WoNOokX>y|KH{U|kY5zJNMx&66!{HDSoFyMekV!>(KdT-~_Bn(+f)?cX0YUWR`) z+eQyZm;GNNd>1Yxi}|3J)&{m8S9CPI$o~5e8!@t!yugc4HGGC*W0ACUb;mkm;hQSg z&O%`nTvVjK0&b>Grq-(%KOP$E$^G+x#vfq_VWfsL@*IP{HO zd-G)Z0iZ*-o;ZMN^UkySPCgEksLExkcD5ytO z(EFdyluqc+e|M1AaK6MnS7nYjwqOKb&Cl_31G=~Fq%KF++4&QGoKYNvt8&4>P(|}& zOiWA~0o2|$In|!fS3wIRnWk2_p1%=US0z6pSh_kAlgK*nb7QNgw&PURrGvQE*B)%~H;V?-^p;f!uk%VX))6BzYt*EczH>NjxX<~V#55s#mRut&;$3~+vpbG%0F@1 z&j%_~#7Rndd=sBU%U2P^6h#=Mr#+c$GGD^;u&Ig9J={VsAD{VRwS0ej4L=WN|DhSb zg;5~DyXD%XjBSrMbE6!;guxxH9gENrY(083dBsazhf%kF`*kTsvYF2|^e8WgvclX* z5ysWNPxkCi-Hz&oG=(@~AMYFu=NSC||L1e%@IvrrR}e2~43x4>e90#9A`q2=CqJ)A zt-{@3NBP+z9RiDCBz*vSJOX@&B8xC~y^^1jbWCxuy<{XAecMubSD9z?&o}nB^S+h~cjC$E*9P}bkLFhR z_z1JjD*wC_uji6Mw9w+kiaLqr&mfsmM-PAbRCT}jmm@-xu4F6viDu$P zG#o@tw$aV;Y3mK0U+0B`heJJTn+mLR9qCNm)J=MRR1azCiV;POm(e zi2nbQ^zpQR#%%Y+`#!%{v4=*kL^TTQ9Q=?A>wU*!;w2l87%>|_aI`^V$i$)UMDX1a z@>ZF$SKr&CY5WYUf#i?3Ipj;5t331Udmb9s3ZF3xYfDC3g$nH-{Mer@ zR7MrHCtSUKL?MLwV{lcBI0vMm&4 z9dw7%I3Na>>w~o1+ui*NSz}GvMe+vi|b8?94^{ISpG z;>SJ{E74SP<&z+dgO-7IQqxz==EtBxxVPrC{olSaa8MuvFA$PGLo@guBFfO2Ex98R zJxhQfgh6Z>1`Cg%fCtO|_Q(GAOZmrVQfXRVlMd*s5rX2E`e3)U=)C{)LU4G=*1)9Z z1?t17Tu;G0z|@T;ia*}MbUhQAjIoqNyoEHZY=zehaeDYyv!nEm+YceVCwyW)B$gsW zXecOL_}9lBo~s;d*N70X{CKY&6-@rS0}7#5Q}eoXY4>;e&6^KYD2*KSI{x`1*T>-Q zsVx6uGP)SZO}2&WV_*4(hK2~`D<@yp{=Giq=n`^scc1Mkywd*bf$yj-(lkv2_a5_Y zs7k$;z!Q07V;EL;91HhV_+PQQ|KIW3vFDxJ`+mK?CUZ3Re6OQdIjua$g6ugB>eAS4${MY^92+4r5d2aiOCse3)ecGPBT;rzp3R*>yj2Wp- zfqE~Oj8Xm782tUP&`m8^}f13XrOvzY*?>UZ=3FL(yAZX`yO zPj7v9e)7-2#ebE(pe+&VF9oj~I&YKDE*Lk>WH&MiNU!tQbO5eo4Ird^{2YS*o+5sg z6&!*iJ?b8q-R^ZN7La-zAOVu3!)rzS3F%}vFRz`C)oWan!{#n$)H~kBS$qEV!Nbxe zW07?t;B2rJGC~#9A%DG?tv%=w24BoTUSF~Q&H7ZtMx62Ew^FN8ot>RE0N6*Bzs1nU zoED+h*TP~t0ZFbY%{R4vy(rkGV=^WOG}H8p%r4+VvZjw zNLaD2My5$S64#1n_jBX_oiI7%=m(h>75u@8wR1PH^Ib4q?pU$LR;^i=R_-p!X|Yk; zUc*+;Yk7__D1es-GVIv z#TWs)S?-OtwefcKWp)#@d^9OaSjXkzGE=JYNrbV zn8b<-h>=HfqWAeeey9O8%GrXBtg{0VgiRqMDku(d!lEjr{HtGJpvB`y<})qB!QdB2 z!O>W;>yI_czsaQjc*3V|WuV@QvOVwQ^v50>&UWSPNG&@}@|8AkzTG@~i&RI^(&pJ$ z=AJll1L+H8>w{XD2Q2gqq3FQIQgc^)b-M>-aorxzvy!|^XN`dW)Jtvc;`VsEHEk%U zOQEoc1orYxbAsuhK7afOWm{q#+nc@AG7SvHPZpXtPZqGa-;NzS6xN*i-hbZ4Z)c1eH&b0( z`x1ho1g5_6)uI!t@J1PPWIS|bwte4<{bk2?&&%<9 zd-`Om-_9_I`6Iyz+_${+rIO=AWs({+8D}=P?TlUN2~Fl(k<`!64Oc4K4nE`ph8`yY z=@~s1>4e6`_JE7vC_lf2aMO*#U}yxARZxIx-IVwuT4iTwFSB*0-1sW>Fy(dF6p)h8 zvwQrdYYyW%FHY6mY*mRZgxnqrFal+{NUKobV%*OoUBwACbwTnCnvAkn_$rMYA2l^V zan5mg7pIIl*FKP8H?v`qG6X-V;?f^f?&!O@6a3;$4 zZg!FTj1E-GFE1%6DLen#_1)pc+>&m%r;~{*1F(MZ1)E0A0{`05F+GVbNi7qa^AkdA>Q*{ ze;;z#C-ahLhdYtmbQDNt^ zb;s2w$G$X)K4(~Uxa?-%qhD?A_%sH*9S}e-g+QdX3j&j44I9sJPCD>-MQM)kN;8w+ zSB~?>ERiOz!Ljga180`NYX5PU6=k>f#z-=0_Ip8V$=}*q=0#zJ?VABLc z*U?8`E}vpIGTtsm>q;H^6afj*uAY%*?%6vT4;t-5>u0I20bDy1x;o+D7hXqWCYPID z3g7OWI%B2v%}aZH2A&+=A#)!$nGi-9PXwVbKVJADW|ZDp^A?DzP&wq`=~KEv~(X~oL@v9f6={Ei$(a@Y+JGzjhwGb9f$ZCf+r zwbah}64S@*J9aFsLpBdpu?3IDGi9tB(3gU#p)A)CUgeQu9p6wzO?oPB7oLKoCpv4_ zqeqXrRL8uV^DDoPx1tR&dD<6>?Y5iTDX;Ev=H}%UY`^yoxumfrB7DhthRFsQF`X-V zK3a>bY~lmp(2{@PK07Z@b*63q7eBvaWP5NP%_;)cKC63Q*k2rVs^7QC15iTjofBF+ z5>Qi@aE`v>Qe;)xK!iG8O#9c+JgA$DJ8FZTUuEPGkOTTK;-3 zlXKh}@#9++?5jr8df1X_B~^hl0^;E>WAyz@49bpu)12Bg3*wYkzB=I9*4AdeX!{P7 zNf_a|ZQ;Z=aAa_4P6#px2`z}*6doRa!PWJSM^3>xe)qe60y6EvK)Lni+_F`9aRWk0 zz3D40Z`&L{^r39~V)^Y&{G-SAhtZSs4c9iM0fgP@qn+^Z3yR%E;^LYx-HQEd)uVwY zYRLu(m^jtwmM$Ds(a7%><#Cx`g_j+^`CN4Yn~+AtPATQoow*bJ)<1@$&!fDiWtVSW z;u~$fBzN*!V49}aZo#MPIfR$yJnl`(a9mW8f}lD2kZR-Bkw#J`1yj;Xrk>9$NZ2!R zLHVFqb6xt}|Mh=OVNUEq7>p{fD|qri2g!8#(a*b@t~5dS##@!S$Dh;dj+w3sZwc_k2XodH z{!u_`D@(gSi(k`{5Oqc0@K?x>dAbh=qgCrYPISjbAs=X`9KKcX2e(N{^hSjRVzU}) zzRcsSaKzU(v=tR=@%NqA;uP0CcE>q_>wMvl^F5xy1U%7*v^-{AezX7baoK-NS(;I@ zDEV&7NZTK%!Fh8g#>*OE_7i6;sHi)CZDP*krQ@c%PFeOK+!Ny{rKqL=XwFp(Sfzp? z^@FR=GHi((@oa?{#Yb_@LMf-upAX#JcI)cr-y|Lgjx;ildT7jbW6vtx%?<-kb-YZ* zTE=7lm8E!^F;P*%&a)f4=eBGB%9Sg1AG%iD1>P6t{qS1Y8L&QMmX~0gc(90*vdrh9M+#e^KD1$lSD6QJc4pA{N zwZG2(p@O8i;z--hwTEoZO}c9T7C?nn!EL}@7BI?_0bCp3dok{0DZ8}PVzF%7qfwEy zS3mZA_+W1Hv7%U%%eN11kk_h?yqmG8@?_JsPfA;B8_l#{w~pg=m3edox)&{jWcI7g zGDT)t7U)qGHg4ot-%&J(K|5i=PW%h1nsq>(Ucf!Te7dPTle%9x(>f|tC?<_zhncKw z==JLrOXEELB1$U3Nh?<_c2xf*nS;qJ2`y-8Z`tz-B2_{=^m6SM#t#mgUz=_719v|^ z97%^4!gq2fmoqRQt@4|kzISeG>&`Whq}!l2jf4o2Q06)wm(j5&a!ukr>KK({i?I@N zAp?$O&8?5rt;x{b`|@RjJgqMkuVCU4c(gHGQ~8YNd@jMYlSNjJntaUQQ-wy-4P#@o ze2u^WC6D;XrUx%X_r}aplOA~Mr_)dPZK$p+-CGtrJ8JbqUgq`{x|*@C+eYr+uC-QJ zB;;Zcw3ZF2NEoB0R))Q9VC~pkF z8s&1KnJ3qcVAgP66yz`Xe4l-E47;=<4|@#Pv1B2!Z@S*L+F9LQM~>dSyV|8m@KdSl ze$&7BpR*U7GYncQyGzg!*X`v(z8$SHHK@Bj*DSD|@xaC;rj>u%kKb}~;ZmSChT`wk zbO2`EEO`C}){8z$9s33l*DjGy&`z9{MQRV1uM=zi^8VSwP8YRPH`!rZBtkbBLkah? z_nYk8xowf~#k$p=!iVw~-&rvK?19CuBflT!Z#?!WM5zD4Y4I;vqJ+BN)r9fYWdsBJ zxj;A<-_$8pXkPJZ;l}30T@4XV0{Iz&T4x>8lh)!EJa&z(DA+u;p6SbY7pMEeSfV7D z$MRZDLZp>a{)dt@hc#1lR_U9*o?^W;%R~G}5;*_+$o4b)S6N_cNl;!S;CH8OtOz$p zGoxpvM1VN=5_zlF%Xd^|9)%!j5A2|iB17ft-p55P0x z%hGBS@KAft1~?Bi)q@c8nhn8_K7MU7=xg*^V76u9#*4yT4Q76?JOmst3+Cf=*|hY) zDuZ+rCsvA5VjnwGG7N&B97)}&B09id>k9*?i@csF_@ncgu;^)sJolLw=3nPmA)Ls5 zIQ;Y$Hv_{#k<*s%3I=Z$u;B9>Z>=l&0{IvW)R`ot{^{!PTNXwFay6b*d$>Pj{(_SF z|A~2m6MaYIqeuDswulPv`Sa#FkySSk58ej(yw2X76QsW=+GSBwM?BbcJ+v9uBVx-z zc*al-^E05y2yk9}yGik?{auUs&0Sqx`?&lMr;eWj?NSg#QA-LBtj!eI<}y`m!^*0| zb91c04ZpmXDEM0(bMf zQEd#;_;(QT3FMww!6Q4#*ZPl&SyQc4ip=iW zATuQFE{_X+^}uSn5}2J16b&<#f|rl--xS_8iw?vj-Ah#^Q=8u@1+LbBAasT9_IR7- z%5rU^RKtSJH57M_YEN#iHNDaGu%0nT`9FQlRU-S~*uE{-ij0tRt+F*zY}a`N9I`wn z)dW-riAVY1!9;_mF*}Wk^(OO$ocUMNnlUV*2p>6xvQ>}ZL@IBOC@Y9JTbb|wSj9Oz7M*!12rnE zhjd@?^r|eE6vl+VV&(gWxB%bZ_-fxC388XAI+L9*N;I|pwWZsOx5I@u6M1`@_ z!-eulhX?1ZbKzR~ltJKo!R5Fqce!u$G$;;8YQj6pLk1vQ;sTibJ z8@Oc;i(2s98XM#%n2S`awa7s@9o9&EryTLhnXhpA3@!D zC-&m@rD!uyjBZ8MIQK!|mO*c{#xVl}5Z6qDj%4`?ojiytHopk>EjU5$uU>9i=248` z-ls7o;}Q%X=Rq5_d?m~vm5}hs8$0cu- zevao)x>Iu_GR|=}PGY<<4UTfJFGbE|Q{tTg#V zlMfG!dpLWy{A`Krc$acdeuds&bkV6t+1cOpw|kX93*!8HFCbktRn_OM{yNjo9F+7T z(V|IUt<~GS8B1zqf$J|>4HoDr=+s$vH`qm$>v945DaKfGt&w5?ssPrrq?=R60k7Ll z1km1G^BF)%BZgSwZJgNN>DQnHDUt5$R_Yve=5Whj+*1qW{R`WRYXmvErrdF)8o zl%6E74e{2A3mESFhH2x(vr_GwH&;vU8_W=tFEsEt7LnZ?pNn#8iLi-y`-^>L zSEq?t8=!8snBW-6e^Iv3o6~sUr;K1c6M;qM?@hDAQc@&!RD0n5R1Cuj4JZe7vgDM5 zM)v^QFNr#{=HQ19~Xp?Hq^7?a{gi-6^BxDQ93I$Z^e5zQk_9?mM#tq~8!%D6;Hhk~C zRX>S(z6>nH9^Ibr$B}&EJZjny7mR z6Kn&Zy8L$M>*p@a<05T_=ogbeJ|z0>@n(~_=gisq zE2fmm*1((K8Me*EO$_D@$K0zYAY3;p5lsJJ7!$eE6r#j~9P>eGO3q z7;O3T`9ZDeii(Phn-=l`KV|*rkrS7WHa%#+H1@EsVt_!-q^%AgI$;y*)8of)s=0IN zI9-1&=f@9A1#;NyziywOlyUc~Ze%xqH^!D)lV%=QH#C{LG(Sq;rdXpl%w=^7&(i$p z>meb0mxGG)clR8uz_L9dF{6#WkJ<8iJP1I zk*1l@Q%1c*Bm66sOnfGhgE-v0ryrv))wD@I zttPQ!=>$IdQ8HemcN!ZL8wE9Bg2fX8^I!c1No#51vWXXuvlj?kLFD2Bmbt|`6Y3%N zBVk8ygd7H3H!TH*6aT6;oz$9rDTRs%0o@^3*<2>`H`9aU*D8-2Y8?$Lis(LjD=N!gSsFsX< zICjLlp6HhS4ikhiS~4b+oj}Q}x3;#!*|* zZ4(z5`E-{u?N8dIhlSmumjzGn5K9*D&pjCue{X0n>c8ACMcW? z;8x7x!sfDD%ZzwFJl1urza+3uq^#}sxt~#ed@}=*fD#N({e{K1_$xkR(#D;ix0%;{ zRI7j8@^~*lt?RSP{LNn6Ry?U2`_^n6tNvkrngHi)zk*ZU2VVjx3?Z-{FU4Z#`5(Xn zQ<`lvqXIC}-c2rmCzxy!Ixd@QP96olpQ7Lv39%@gro#Y8kpT~Gl;!!#lFc3gIzdlc zBq6mTO}UO=$bE$it3i5w#w6k{$k?xp;%E3WOw0?W_}${nGKrS*d~6;qYpwXVv@cW6 z9-Z7MaDxh>D-MMMlbV+x2OLup^3kCI@ z=bV3ie1GSg?#*6n-E+@9bImoe2#AQPSn*dcfc};jMqX8kj3OWJ{Ki~iJ;g6^Z#pS8^FZ>Xw!Q^J5f*)5C3ysgGl*%DN-N@4we@g(#j-0*Gc~#LO>^O^s-( zkbtkK1d@!4k{N($qSxs_`H`(AF9$+v?6_8LcT{5AuEK|`w3>B3F#u>^7o$U9B;yEB0GA7lG50mrt;_m{ zf=nVPk)kOe1_1;8TF9OpwX{OFtT-@x%sVV7Xim!{78@24=pDddcPN>0*r15YP`xUY z1@f%72`6A6B-w#G&M%WIAqQa@H~=&a+*TLmWSno=S#oM&lWIoE)&<|+6au}ir$-J* z3W9;9xs}OE{dHT%1x#O}175ZeZUwW1NUXsjZ!}So<#M?vP*wxXSWF79x}B>>%D^zP zRk-=27Krt~F`fwfLc?SB0l6XL?kBqd+w35l(Jn(TWWFqv1$;OKVqt1m19pL%PBud* zx)Z3?CS{^4<^u-K0@*gs2)UzoL7{(yki;>!UD-cMyMb_(7U$5uIO;_r(8;WOJEIOj z3j67gd%k>d2ZnC9SM~sth;o4fS-as$AgLm&3p)!qfHgn5p51JCv3qV4>M<0MF4A>o z+yfGiC@2rNGVBW$f&5gY(6!!AeDlD47wHs89pviV4oM$OgmwWa^mSmTfL4-Wj~Rxi zUUC}1NKH9xJ|W4ky&bnl=eAzzy=QGm7>~MGh{|ef{R#}w|DsRPd=6Z>6Tj;U=n~8?niGr~tgGlWD@^O`-xIsYE8(qk;^esp9lqHlXc6I&t~02gQ#{ zh5R=9l0E{j95#$G*pBl^yAM_XF}cH_x3#zT14#Qlh3Xk#!3=7%gIt6cr`0(6W^j#?p0N>CS8{ftZY9kV*gI&hhx(q7CK9BF!>{C9Mnp!*XIq@W7&cvp3 zmTds)9V#1k9bDn2xKs$dV}UQ34X8TEy%+_CSkkeYBffB~1E{8%g|}9BhV&o8`}@zh zn&5y&2f*=3-ZmE876p}E6XN45sB1(MEJU3(o8`#-aG7pyCQ!$KUl+i(=LOQcA&Obw z)Rh6QonE^Q0eBOZ7c}gZCx+M2SH(pUo+*Ge%vtSa*&x47O;rMYbV31ejeGb)luw}j zgZ}XLf2ZUGQO2t6i*KC(P?q7ewzV|^Fn>n6Q9#460^O2>^0SpYzrke(^EG_9YqLam zgi2jEf{v~gh+f4Bzs=;V)}u{B0?d49MS?NlEyFQw8=o>}0&fWD_eW}}0mx53=)k`J z<{_x*zI6e};?`{dBPJ{Xz%B%YQ)Go8pzvqlHlGZz*Gip9S3m?qv8P~jhrzfOA7cW= zlYkrO2PRS_0>LCJ*Dy{y z9drXZV)RiyC_hdi3qpzdom~~+R0e^b(mY_?{6=c1m=s{% zhYK{{#sNtba(mQv^asv&fs-&q=xy;nC&}yAZ^y^SS%CV-Y?-WNpqG+>kZ>I^R2o7y zR3@*lN~We%HYSLHs;^XAdc$*p5S5`P^jLq?&HZ5l{`Dg!i@SMRq?mQB{dq#}748=Z z`X_Znpa=L!zHW&@$v@ZmHx2p6JK~<-_RiJPWVHTwm;d8#TthHH_~`U+MFsvVE%?V9 zJ#b$Yf9Yd!KMUX%U!1qZV*gRB^~VkV^%5mt19edU2T|fztiH5#0N&XCKVBlQ|821` z-H;W^KP}?F`tN5Bpxz_-|F=#1&qn>UO~C1*ksKWSu%_?g)iQhWwKOwZx(Rw%;&lQ> zI=^3Zs3;HuCH=uSYDiVTDt2U&?a8KqU^5b|{%_sYgFMY59k$w1_N5yVnF|4p+Zv_np{ z3hb{AF#ftH(1KGgaLn&-d56N>9AWYRrQHpE(3yJqmmiaDcvgQ5sj*TNFYoiRHDk9JU1;4F*vXa}y zX(qM{%kS-<<8gD;MkhwOhZk9pQ*XoGH9^4O&P8$g>3N&W;6hmptN=7XWSWDytDL%Q zhgy0R0YgN3E#p*9DbPlb#zM%dynfQ#xLT*!I0+VGbhiBg4Yo)Rh>2tDXQ z<}a`Cp$oeH1V`o3oiOJ-ADkelC7M451W8_R0m7Cx$Njt0(Xe!9JJ|~_n!IY?{CA+B zK?dlbr^aGx0NxJ!Yo&MpiiOHMO%Y-JXKUf_4T!m2VJ_bU{fdToh%ciP<;0d=-ZX<@!q z=Lhz(@yribGdltnOW%tdw2nyBASwIGZ$-mqZz`arjVThue+&44JQod9hWJ|TkNxX1 z)4w!rwf-#|H!e+x?O-^gU5vZUWka3AZjdGkcniGt5iX4Cf+Y5ymH#(3;r?Ooo)bXz zK>M|wUuZ%~*Jz#}4p{Sw&}91HBEec-1{_U4T)_RBUOzUIDennqjJLA&xKf!D7(P4s z^{xs@X`WJ7I??>IFt9&s(>exW#ds4T{9O9pb-k`5co%!;Nr zNp4aKSZf={lg8aCz`1CKhWK5Wfl!dbb<84aujvjif31}p9~=8_eW0vPX?UKaEufK4 zia?Mp5TIxhOkqWM0{-aqWrUE!GuW&r(pn__?zn&h7m-9)(sVcu`(Y&#cSaFMOApbD7z{rr1?&pc7 zTEZ8HlF((Ug_tJQ~gK3Y#(dLvC7)!XgX>rBKY}tXr&NA5{ z(848|)I`FlrhhNU^gWG9WOT6P*A#0r&NO`8U|+xQsp!AufcQEnfnMDCyi(z1$04=- zr{&Ay1eW+oUhw?2%IGUjffpN*`W+vq-;69#ebS=8OpA|ZEs$+`-XE;-n2Ce4t)nmf zX-s&nbCrc<8W7zoyOK61BscMk4sXUTzay`GVod!umEzt!&56771s*RYeaL%s_YpDP z2Yp*FpZuceu-Ig;JwAA{tM2Qo2_)BGu`H?cBuv0E9U}l8*w_mQLBv2MKS-_T%rt;X zGQKbHKp>!f9!CGzWKflQwoSJK^Obkf$z0ZYss2|aNF<7IFCJV@BIPK~ zn?x#3p}~^xTCx+>C`q4#8Gb_zgwHnaX~;NM=T}`{52LC@2BAxX2dR!}!o$asLD(@d z8S!R*k{dHUmV6mc9ppf!4x+j9$*Pgpj^sh1X@Rj=aEj_@$v@T72cv5jl6yPyvHUtb?t7`dEbR zddgGBII=XTd-MQwiq25INo>qarYJAZrF3|(bB7CniamH;9P)|oMY(JN4;4w|nO6u& zw}5uFp48|Iwl$6K)aMe{EPrUahxj%)*#ceCvdyI{D|wW14U->`Pbsv5fq{fsCCyHF z2&P&B)xUMOpQzx(yV>G;n3Auv#p=Y)CJ*fjX9Nb_iVi(bI>6V$2k7n&sxkF4EZyF^ zN+mOD%~CFocCe6?`)+9et0E3cLL)!@a4WIoK`Gbp-L(<&Ajg#|G<1XKLMI4)P^Eo? zb|1NaMg_tV9&ek*kP{UrH+G)4RYVSB3zd}yGTDQLMy=!$UeY8FzvCm2JuAX*%zE2& zUrh^KlM4#YSh=vR!uIufmbHha`4<8j{~R#091;)K5txUPZDvyQgPVetl8j$in>OPWE_wxat=t=v%^#O%vFh zeoBWTGq2pZ$^j^kZu)vzvYJ^5TyLM}o+{vw87#1JV=gh@EMLiV{x-M0!&XvE@)V{( z+w{~AHTaJ}t%_?#Q_sCWvW)xy+E#W!%sP+Qu78GLw?>)!L~u^qScm>Mbr zrSzGWA=bg>5H=(FmCz%dZ10a-1bxXjRyx<0#X$9?@0EGj)>IbQl7Es+Bl#DL3m8(v zhehD`l7%GHm}u69qvXYc-RXK&Oe=}-A%%+#o_K&cJo@6m%;`!*z?p>ejAGzpnYHX- zlTtP&vX*;uQ&X1d;4#MWCf=6HS*1#Phrgqu`c5L^PqWpV4QoRe_Z!(5)WW1=HuDY3eyVuV{v4;fmA&L|#(3`?=pasu8sSLx(W z5QSZ`8WbYi-9IRd9dS^;{fSz>d2;}E9D{1y^`&8|RH1YAogHysMQ)p^QRE{E5tbZu z@Z?-=lNYlog{s{YPycj1lF9$N2a3f z63^r>e{Vh9Ex(ieW`d%# z&SKl%iNOAp*(TUh3+s!8*yQpw%Ode%I!8w3KT{6Gl8JJI4C_NBP1D$0ZRe|sPpQs7 z=UA&*WZ=u!?b*u^LGzV!9ivfv=m3dGb~Iae_U$pL4&?@F*_^*`x5=@Td-N9m-ogh$ z*-%I&m}>c8t$&3$sfc$9loav2!+5+^_1~uJ&9Z*6~h(qQ0ur(hQprvaV zmhz!#(G!ENAoMFyT>(NqBFr;j@8AN>Nu|RI!&UH0nbAg$2{S6boo%U3^E!Pb=9$#`ZT56xs7NBW3h488Db6I%3-;P5sSvLg&C)UTe8Ig%^n%g6~0O?VEu9dtuj*uZs8UNy7n@&OZpWejxrNM!^0?~W#aAd-6Xxp@`QYWWmD4PqY@p;_17`P&9d+2pDgOA_8=b)XF7G~W>_>Oi zQTJgo4}O900X9}*7>(G5&h?94m>N6z7=&j2V$D|)6;a#jU(>_brGVMAz!-q+ICIHy z?AlJn{LxkxqIPT3Nqlk`7^FL^vq=?HW9TyhPi4~^bNE>|z}W0&?hC@*mmX9>#e8r+ z(<~^kcol*1U$o77Ub>ohNQ!;Rg?{?r+3TTNngk5iLW%qER0q9HF~d>m8L5q0$iT9{-1Pgj zd-DPTMee@oJh2mk$7dDNCsq$3fY*apE(0-Ki1VdQN!))uhFq0+U+O*Z><}lYR_t z3xW&PeA-EEX=Bpo$C@wE!L*{dD3yNlnwySXAUyG>k{85q1_AAx7=J`TZc>IOQNj55b5}Z$Bxn}A4SiD+=&9DS* zi)Ak!utgf`5H89EJ7ab@ZVC3a}?;mp@*%NfL+`X@RT+4?oVL7g@8zs7Ac+;Jj*>daUlNu?$h9ft4G-L`GjAM*{i%UEf+LsocZ!0uM(-ip^1*{qO4e`|`=r-G z#mGX@l-9&|g}ClTFpGL!(t&CVK5-$*I=!=m+jhQ%yZ3WHd|;aJ-^j}2gsv+e+AE}B z30Y|Q4s9w}9Sxct#l98_fR^$72K;dhEYK6t{iw;ADL{RXtTCp0K`DrnpJY> zksyCLdWPG|Gkw;R7WRp^zSsy4KdGPij{p-U40mqQ*(pHFV3<|81(Z7pRiQ1aRv_m+ z!Y1sY0-M5BXa-prz8;?Bp`vrZ&GVv~=_i@zu8*?2h|Mf~vlc&p7}SO=tSQ?T=^10Y5oAdMaH<+~w>`fMxZ90U zSx-4536J{o`w89QV--G)B?bYLpsaBsOn>-wO2MyKL+AMAK|6$Ku*HJn20A*By5k zs{iP?xVd%S(d@jNnWQ>Yq$0c_&fF?4@2V65%HpOZ{Dw7CnyyrOd4Rd0$K0*3a^?)b zaNkIggtiNCPra|=W5*_R{K*$qLp*t)j0pfclk3%p==VCbdpcje20BpQfyCY-gF(b< zdwBk)Ai0&aj1xew!h? z3HO4HR)BMdGriT+C?AR=oUH!~)-@v2S*#e4*_BM-$a=RmC_vIKlqSO_jkSI>ykC=s z*U0pShvQFvh!cotETvDFlpF4is;?MoD$Ly8tCwLqE@ z7Q(`l`|^s9rCNNlRA`j*4S(GFbzuW|p$?I3Gu}1dr#Vep?L%E zRWi-3d;8VC3XyjClQ^L4qacz?kv4r3)xL>8H1QDymbf~V&5`E*7qJXctc((5Gwb7e z$3UX?X7Flue}J~7(AXnN?hpe zyI9FGD-Od;P*vDUKN`MRV_Z$=cV$~e&s4~~2kD!{a|`T63oi}Ojb=}4Qkb3gwrr(I zf0~$jMhKjpSD5~KdgPa}*+Km9np*m$i;HA# z^dk;#iX;Quno^6RdF5voJ}bG;Mpx4{O=3Gp?#O3%LG;}{Z05YQc;!los%pXazSeBS zyIWnX^iGETJEBtYUsI~6a%@I_@i_YcM8g>+WUi*?LkaRIBmAV zapP-Y>&5Q`HF;Ou?|J9hbvApE1+qO5~& zVNl%lCq{TM+yhX5E*S-J_lm=1$(xeHS~xBx!-0Wx0Lcu2i4ws!nuP$zb>;H?9x;8M zl-TH#YUx0Zvs9psoZ~5`T>_fU(xts|txcL)U**%6CEt5FH%8K`M5`@LQxoy|pT;nd z+gZ+MXu%?hW6!dhL+0PZX$vT)I)UR6yq$uBDDMM!W^}3hGz0?*AOpOl?H4`HO04{J zbz@5^YVX_CM6U$Y(H#Xch3RyYts&kbLYDr}__zB4T;VT|hV~QC4L?;qE1hmus|Y{m zn4e$Fs(G`V^2An;bi;SgFm|5JS7l(8XecdWQhNLa7eqq-mj^BU_Y}(y1URQuUv_ay z?z}Ixmk}8P-rbAGe_pYiK7=GF@i8Ke(Gc#u@cI^>raoC?SYG}6?xQ^@(YPO6b@n$;i+q$k#O^{Co=X ziVO@gM2+HOQ|{FBlbozwP|0Mi{XAYF7$+EFsfm1vm!A*&jHml&+Rz6pDmnaOB^woX zw^`+P5DxgY6-b?$z~0{IjFBTL8LOmsB=$}EVES&kz3Q!b0c@5MWmyche40jYPd6MwGb1o zJZsGdZG=I%-QY}@M0y-AIhgGcJc^l`2mC5)vaIBuZv$wg3aCdc{?H0OL>%=<%?x3i zeM_ZJX&aJHg_zydOrqWhTfZtXI)s~t*isA5wMLFFhdZ%!&r3&biR?$FwS38K0Sy}h zm*gmT&+thi;0jVc1}esW0A?;JIF*5(fv9XlMzc><$#Q9Yw(E@kL>Jc!=$yk@uY0q> z&hxKxQcld+%_U>d3I_TzVFY0COCRjze3|A%9HlffsDU5l0O>q+zi!-;wX8ot_Mw;s znIYgZLU=~rGax_iy1B3?6R4ADZm`&HR?Vof1b;$ub$TKAmBzY z6J2)#4C~k%=hEMaQp0j_;BkwUgs@$6k_#^0fsy(XhW%WC%tKxMMq9Dfp%PC+`u5Sm zDTEIhwOs9>lZ01Xln75&5Ck>c%LqP9XDZ1+(Uu(cqnFf8psJZJRat5Fl5$kTi&Ld- zW4y~6>3jZXNVE(4q%o)nGU`l+#r`@oTbRe>eL5OBXtyrQ-uJqYsKmBwd|F*v)Gebp z()kqr=92k7vG&KBnJ9vaxg5`X^#%C8?jbX-mmTdgn^0*Hab#5aULt-j<b2Q&=ltijr<&h{_=~GF?VjwUmijRra~?v_r)Ps`ZU>;C0H4XiAav8v;k4 zA{VV_Q^(%8js!YkI!pc)kF#e^LQ976yE0(;?eQC7tjHJ{lqT#Ny=NxA4qu77ZVELY+Z*(wifvPqYIfLbBe@%YKH3bqVg*?w?-Wl9M zn@W4uMKz$hLnZ;wjZ(Oc-SHMT8xpFWFFdsCPds%O?4uw&-yDd}%7X>9`*6Ah1?s(bTM)s$!{a)Q?ci{NbaHYfi{cGHDs7IAH zWRqY@mSM{A?1NqtDK)p@m1OA$6@NPuccJhyq#0dZ6YAfu^}yWH72={Ykw=&0tgz#9zt6z}&`=xNhA6h(?Upv&vw~?uOYnEQ66dwR* z=vX4coHW~w^~YiO^C7v0pvFvrrg-gtirjBKb!uMy2lf1F&P#VSyS-0h*3~(1`L)@j z{L!qcz>6UUV&~7IIdA?_lDKqP>TScQ==gV2ND;(=XP(azAOAPca3`aG`ZnNk!E|;? zwe}w^m;d??|NPzm^;QV@E5uY$|HL2uDW|{Rx=Gp%x592+n&D4)_h0`6aO)|6-ZFOx zFaP<__q^D@{cH~f@DuUpVZYK>|J`kFpLQ-2P~d?55a$2Q^Kr2~gbDG@;L!PBiGqog zD=79qTXnlD|JkZvx*72JKd0*F(f-e=`elRue>H$X-}SeDyDI#O`ua3%RTnL%*F}0u zBt#u4neMg1mAk$PYnPzub>nv(#h?w(Fr zxv&kI+O+D&_|$BDdWZcWhb1Dtqrn90jp1$eRnD2y@JEmMrS)`l)*@!BMb9kv54Xqd zNy`u5yZ36$lBYC3I@g@b-t_5zYm~B4JDg2OdHCVCgAdw-ER0^juaagNPO#@=Ibtxm zO(BK|yO|4H9LeVxc8(Fq4TRmI=+yZ7R8WifI=wI2J;~Ap+338!Uz<(yoe@!wnd4)7 zB``Z8jNLgpeQA-H4)J3RB{<7!83`PiUv6V}0ZyVeY8aPLhX-YBTo`gXDL|hvv@JY6 zy53luMg^Y_Wpp0)KSMR(*R``(n5OS@l*_-g;0a3{e)?VQCB{JC;>(>cn`_Yw6atE{ zhw0C&hjJsY&lK6Ox}*)^%Zi`8jI81T$xr3$5ctY`jYQ5HX>)EZ>l&P|+%v>Ppr0OY|Lfrjl^Qf%_BkD3B1@+jYAQ4EMQp2JnCI%*1vSUrLl7>!$JDJ~v;*i8;|_{sQJ0uS z7I#9C;#SQDJ!txM{!$g~u*og!t(-_n+Ui_7BwtwUK~++qH*ex7bQoq~EKxlZlh=J; z$f!=2UrzE({T8=sLOm~|HhpoTt35><@YYYY#c>x%Hv(ViyO%wT3;A?+=O8u6(2S;% znyq-b;av4xPfIsihh|<*ORaY+WR0JeB@B zj$N{ImNeyC{DOmaGk!Ov4J#7v3fbg_K_BfXdAJ;d=d3z2T#1f+g}U@eIAiwc4mr_% zz~TM|T_XUwACt&Y46oL;=nBoRlQd`O3zq3c2Sepi_d?|6AYah?-OXBD$i>teJ&bvD z+!Z6710NWNDCJvd@BLFA7bEYdXyrZ@cG^8v`*FlR;c^A3z$oC~*IOvSmVh*Cl*`oN zPFWIX6k0o;T4n1hestC9JXxoEs1-rHE3WCVJkUNJ&DfpBQuPo@#1iJ3$7tGcI-Xrf z`8ZA{XU!vDXO)EApI%9hO*vG~SW;en^#s~cVANgUjrH++`liHuCu>79HM2wctYgpd z%!Xc*5cRLIWn%PIRURg^YxgULfWkx;$%D@&eO{%Rvqceruc7uGhAiqfbu2_$UrrE#)ml!#X3|3Wy}}$Fa0o%$02WTW zV0AnG2{wb~AakwB=#ADNW5Lk55yvir>8}fw{+b%wufvgGQdhOYap1kJ@yf9!%vP?E zkS056|7KV8;2jOqQdX#uQdYnr@5N*e1eRT@OkOwyBtDjzT$Nl^xt8yOC5mkb*$*D;skEa4sw-##(LzzU%GE-lNkV4>>+2tLO95D+16X}}7NX>5e}sD~ z!mj=j_(8I1s}bv1jkxgo#8oGWSwB&uU1irg}1q|U4x%$gXIF{?a_<_f&t-`nT)NUhZ8@FEAHaB0P?eknQp@Mc_5^j zcd^j|5$Zla=wsYOK>=yoyeesao_yzZ|T&FxDFQT}bMvA8vu7x}0s3xrH;o+muKyT!~Ynr-+dK*3mVKr5HNZ z$?Y&w42(*PEwh^?Ul!LMke2s}k&%g~$Jm-dYHCZkC3ws3vvBME#-Zo-zLBdg+eyO&6UdC(6L>wI;FtWW_Tg(5um+UPt}?C%Vb0GLPYeJ;f>69_`kHQm zw&FPXc-Nl2@=fmz&nG=ftl9J^U!zM)lJTTYlb2x&uFd-*lMw^;paK6X5N}n$c3<{D zL!Za47xd7U$*A;^Dg79Q#E0B!3+uxjNy*Q_E~=tNi%MqL?4`pn>lbq+w$HCHHZL?( z7V>NCym$PQ%KT26sjQFv_G+2>h{a*d;N-!G3gymO4Hpgu65iN~xVCQ#9#(=or9sf| zeCS`3g&{!?51z$h+>GV6B%*;VH^!DeDxq}5n9iljX;X#WOeQJmd6j~2!`9Djk@fDi z(LEI~lXU5DZ{ru9=%4r)=N{k~&$JEMt!BJWGJPTa=>T{c%G2)A(VO=l$${zdKd^&V zoK8%FVW3wj)iX;qnrK_S!N;iijGmS8eKo?7&*Z$=S}`e_zr9{Yg`W?h2Mh^9^@D{7 z8aY4Z7L6$;z`YnYjOh${y#C?$9U;_%Fgfow#;u;$-DQVT9k*sJ-!am5oW%1uv1`6uEQmLoGIkla zO>+X?D#+4a*C%-e#*^nnh)!&y@Ntx+-nPi#Z_h- z_uZ)tv2gEnn^}Ql!V;-{N^``!TPjXTBI_E<0R-SmgwIPgo%oJZj zK72VCl#$Kj?SMBEX%qJ8=O*9UD%6Kx7e38`uFN`;vbayJF)a056l;zn0+}@}o{yJ; zYR;GcA``X1W>?)XkZhCg>YvoIXsX5|>_WNChw%~u{>h26g~Cg9-A~!c3<_{kH6Mu*EE=6b4@}(*ct(RsQ*0yvrhwo#3b}df^13^jYiRaL@z1T z9I9{VN4=7=e#46%3;P5W)QRJ4wB|F)ZUu=fIDxW>)cw_Q=}6-N{E;QUYAGzHGER-T z(XnWUc!!x&eWI`g4tiH}YXnA_P9tOKsyCcX&W0uyJ){bGu587#gyBO4o91y(2}&tW zv?efjJ2~^GWOMlyUjNeb2ats*f>F$32>LI$Q@^N(kmpX=<9&wypd_neE12};n^|cV zD2tz7Zjej8!RIPl8GHZ9fi7aPjJ z0VZz%ykfxkQ*B_$G;&J7HdQ_Le%<0*F46MqJ3ai^$Aed0HV@&0EjNS{$O}N8vq$do zYEq!t@qT2mcU@jXTO|I=?%fti)3rxi`Ma#_+fDB1RV_7QUg$5*bQ~P=MH{Ofk3J&E zy{odi6p{r`f@jci%Tzu4{R3Z;yeUo;SuvSi@i#ngjSqI*d`5e;=T8WFj6pVdrSm3I zy(Iq$$-V7?fXai#zriFTV4>A>k7rUcn+@YHtF>n<@%Hs{goi48XI;TkD~aYgoV68$ zVE=d-HTY%7U$?*{2hvX&DS732*{89meyTiBuWvcDpwe5oVlq1T;fG;?LQ=+cJxf_1 zL;WC>V~(nRqBrYrOwX)^T44f;Xr?uA@193~!-$>pXqawznkgTjidVPUJ7 zP<;BsVBvBhTDa{|Ina(%HP*R(L810{xrQ$nv^znQx-`rr_WZ1&te$YY47;zy~0)?ugj|d+YVh<_CJA*%t*;tpa1gUH&ne1ne3?2!8bV_X{1U**=V2;)Y zAD}t#6PjRep)jorLrkApN*@`3*zxIFC|{We-&P(83f~_8qDg}{x5uB$0_I63$RvSO zzDxSJYh0<^I4ye}V`zOZb9y8Eq$Pim)ig2#tVk~l0+*lK=!nN>_)i|MZKi2>cp<51 z@n_Y_nPCx*svVfbJ$=2Nv4Rsbq(5-EZdlf!DroE@6kj_y9@XQWS+lbJOmT<{qo_K% z8a?oGSMNA{$5BZ9D+QL_!uCXNf@~hph%FMF<=DAFaj`RBKX+MxxlGX(wV;v8+j9 zO#3(bW000U+w&zKLLC9fz8sd?25}*xyyn6bt*d+~ofpCNMHQ4g@9nD{acge1X6HKN z=m*q*CH;_f;5H)C5nCL~{C-0b=0 zkDt;5<4Q6fKCkk7OlSH6{CO0Rg~k#f0Wv<8TM4M%N?4DJBFzeXb3xgNU7`7*)v#m~^H3vO(P)%H)oAaY;Z&nZab-_G0sz3qJdW;yDPknAnNf@T8VJ#71XL1lU!7Sm+Ksw&E(SGf*&xpXJL3<)fE=Kqo>z(R z>P*o};=|{^D1-9v86(gqMY@f34M>0hUde{l|3_w6P{f^M3#5`rAlv^q@Z}^xn^4AQ zrH6{;YciB}>0|fywbp8&ZClo0?i6!M5No<+JiGBXcxZGp_wf}pzP~Pmto@Fqf9)ab zzM*0_$J5iel}~Z?`RZlDnwHMH)d3Ti2j`m|CzIOqLrYJV&``273nV;|U44CIg3$T3 zwOY0+XN@~$=~o5OcX%=!LY?mLDeC1iXq9PQA$Bx^7kA_-oMVx#xxzt}>zIvwGpQ?r;t0E$H!lAul-JtN&V44ben$AFzYGs2ZE^hw1#3bFALm z`kM<=kNBy2Na8*Hn_F~;LV7+DEU--nx#$530i~)OvDz5y0PT!*w)r+&neu!U-D;_? z6&-;|E#1(4!@L!u>S9ZLy_0r)kMK@F5m7ILDW!?D( zY?T6!$q91T-b9#0<7fQ#;e->^lGE$N7oO7xZG66EAzo&k*0EwF=VcwDUBzNF!=5f{ zI(tzQB&YtS`|~d$xFtNW#N-TlKonvSfSh@FZO)ztcm=Ab_O>{KUK&gKj!vwohSS%&j2NF>>VR`PB3sAQm@@Axx+DQ z?oTDhb)PAHL}66mb6ugPXlvqIjec%jX%fg_mN}GNL>mr_=j(VHGhC7(Dxa?+*ZLic z+qvMTYg`+6Wk~ckY1wvpF=vH-++54B+78V@t~pxIU{0b1jd)n_&8y+bJYJ2d*_q66 z-xX5FeYSwF>*9%VM0+BNmGRD%UARbke`ak}v?uVeH0FNz{v}m)b$%5ENXdBECb9#T-~tS(q-S zYZRg`zBurG#9RB|vPaOR-J-r4Ptn200VoM92Sno$tTlz?Cq+I$ZCWU=yZPRX_wnDY z;Fnj_PIBtXQhL(pWo&ws8*?c}vR{n~QMGjgd?HNy);h7WOWVzlj$H*Ch8K%uPBqJP zI@PwEr}xi~d>dIDH$NFv?k6+*IMEcUrEK!@xL$mDOOG%CWuz4 zZLW(p@Jrsm0Z~vN01U6J#A&}ywXJJpK^}C+hg%{_KN9#s zPLR{R#*s&qAWHiloWA{PgzLyS>C`Rsz_sBhUmXmjq0L}hfheC4ypLDa#@+U6xHZolEE=BPF2e!@2?|KROr>J;CuzK>UK-X z>B8)I$BZ)_+O{P*Igi61+pOi|v%AevJLN-zch=F+AWjKP_yUZ^K3^&d9zV-Kv<&H&`H9bqe{JNS)*N9W%6aa znqG-8iuA&lF55JotXS=!(Fa~o*E~Wi@NE|O5KgQawER5vQ>cpq!xbZs9d2^ys*Snirvpyd(?CCA}SiH z9qTOVoPnZfI-B7fj3;m}HPKtC9UEByQd3$niEu1Dx*VC`4x%(+H&={7gW3xd5v-UI zWJ{5uh*#>i31kDKXj7VE87YGFy9qy%TZt4wSjSxk&-AhSS@Pq5UsORwUlPy^KkUc* zD(|Oso6gF@uOA}_o6(*^@)c){#%o#Yv96rmk<}BO?~wQBPD|R`n%h zH%0kddr23!sKQQBy`NUV4;5F?H0ROXgt8`y#GS>#qRX)w?a1|r6;IWa>ZRdq`iA1J z4!fiU4^p_T(#$7Sb^@lD12GY24r;4?Tslch=*S;eT(yxXwY9fM`=|6x{X-=aw_1+N zqUA6(6Q@pf%N(PZF0jsM)>S1dWpJ*V1P+tVD3@4@vKs^qwBVJ%XRcT2GmPv-g3Pni zk?M}3`Lz~2@iv1nEi_9rOjg4iPD8byF@l_Y)lxNLRZRB;WZqv!;%c;MI>xxL6mY}M zpP0nE)>+)Y<0(YWjah6}HPXs5wlC)S5i9LSI|kAao`Z-{12evl#__d_Ir{H{5V8TrvKhVNIO7~oRX zQp8YYljHNjI)lyG#mo~!gk${V`mowd7GapElj0?cuP^${n+ff!1CYF97qUn~mcg=o zW7YiR_3^rnbMl%wg`yc+(Q~zt*S7YP!EB# zL^=%wrE}3BNDIiK8&pK;5RjJc&b1cZ-QC?G-SEu?=-K z2V>#!FjJ%QkU30=NBqiCK9uj&m@9sOqm;f!Ks+&{Zl209;s#M~A9^cawXoL>#DjR* z)DM+D@b8Na4Xn*fRich`Qo+!9d9N1e={<|Hz^PCDt02#i`PTWdK{9OAt7`J8J;d4X z-1u-^(R71l$7BPK+_zw((ScPUX>Z3!T-NpxaN#k$>wFEL(c? z6+^gULc!>D{@i!VPvir&kiG$I!=g5<%by>$BfE`qWllno&rj`Sz(=sieR%tob~9Y0 zhkV71K#1MRf%=+-_Oy~ev8bb)g`ihpWm;lu6};W7;wh$8hh4-ml$-?;Z^)jyvWOeO zJt5`bI+VvK1shN9@*hgnuL-*1zQy92)J;trQna-o5%l?Fja(~ema~~8aF)~Wb*<=# ze#Z_uf8KRsix|G?->o@lXv&GHn~lYGIK_Xoh;I#vui6W<<1H4X8`#NZ?^s|CCYaGa zgLFZr+e2rjQk#o4i?4y>_GAl4Idr&sDpv}aodmrkECjJQCWy74H+k8=Y34Apa-cS%+|}ByEqf}1Th($%(C~N4!4$8ky+dE|lQxE~vKr=r<|~)%o;f+yk{!Fj zJ-f|5j=qA|>myiH^YWe)#I{woD+vGiwLV~U?#6vT zl5_L84)DBL_^$(Ai&>6|eEx96Rg%bpTjndhm9!GVa>~c$Q;X;e-g*@GW&2zhpf#Gf zFtQXtAzr8O2jKfTNSDz|xB;bP93(y!G%@;uR$Vs-ZuB~ThjepM^EA+KOe&nu$XY4+qK9o`RG4#)Va7UvYbo=8?qSk6#|7bQMP9=gj^XF4OEeQL$R z$jfvN1AxNvgOKJ(A;sm#V-^n0Usg{ZYgd*suo-_p`Xq;`n1$|Fjb1njUn*B0P|=NE z{gHyh?gD+O`Q0xc>VAzoGln}UGV#rIsLQd|Phw|bLA|7H-+ld(i!0-8x5j-NcY2bo^G^qhBDaTnUV8Xhy0O7&f?rgQdC%68i?w20eA z&n_(;g%^eT#Sb4<8kWU3LG-&~#R%t@SW)Oo7CCI*jF}iha;cj$pAV*P)g)jpX=qDr z85q-http?b=07$I2UkwzbE_MgVD3F|*Dgq3V%-c{fOpE`xf($u_Tp-Cc9=`{5(M=l zTchrUG2y?eXpg~S{C$kX9RpB{NLLB3!uAQn4EfK!B!MK^Go=6@w-`+W_ck{}~qVam+~RW zbB7M>6GO#Dm8q_%UY2IHvj!tb%w`UeprjU@of;>1Nprz%PGKzS5rif8yLyqZA-hT6 zLbRie&#IiO31{I?$6}?Oy-mW~v_|jmYTsLFY@w6XA5b#lw^j;nv(8AD)`fU%+o|1* z;Z+PRYrc-da=gB{%ydmOlj_h_IYFUh6L-r^u3=T+_=4yte*g^jZPk-H^e{#^`%XkR zesK4|^n!f;N_DDKR0g+ZfP`K!wQ{TGizd3x?q<4&xYLdR@81Iq$6E`usi3U>7$+GN zZ)Hc*l$NrH9?TTb`7LiD#M7R)h^~CD@XD3G`?Zft+9px7@G*$bbXy-Bg;fc)d5GZie42hE>S7^+)DsnFodrW-K0kJ5Kq4W~w!% zW^?V6F#a3`CtB0?u#M0Auq6O$Ub_+u5s=6Pne?lT6A{G}HHx5^pc~VPX zdcODEwEH}HF=w)8s9+~-0K3_=^0UW=(UrlHx6#YJ2C4jmF)L!}Dfu)bLs_Cj;%Ygs zaT{m49ez;bpmieQniOC>?p&pw3VPg5TtvxS$ME8E!LOv_y<%U|<`T-K!lM=*T?@Z9 z!DCg9vjPjOAi(v!%{IMz5i6>dG>UffBJ=6ZqaCRy@4+6ee$!Hf=rYbSJd){JXc{ym zqUi&7Gp?E?+>vT!B{zZHwn;I9ItZ5Cp0tY{s39$AuG_3sM8h`J4H2TiZ(Ft#1})~H zFcrtLni?~UJnG1Nk2vk&KYdEbu!Mo)lLhuiE%8YvTBNhh$lJ*(FNS@XP3axd3{Xf> z+{@zn^dq)k=N-kPBYO|VaQ;jTd`8hd)>hTxM{ACVtP+hk50HEgn0qhS@JVyfv|t6( zzQWZrdsdNrumr(#~oiP&6;y@)f_y;lT>Ujl5`7;-Y`YF>jGl|hO zrlX&#Y95OS1AN1vnr#inTPF}&)CV(qJ>K$i{ZETlT=z0Ub!19RgExbmUiZF*t{hCX zt$aGk(J52EjJHh6kh*QhMOuida<$vE|FkNuqcL!amxV=09s1|!9)%x>$K??<#MD_L z^li6y?{{9IBQkQQhX@^S_ytPl+~`~E@4XXdrzCe&cP(ZUOZ=5LbaUf-SQz(29|ybE zmsRVv2sVp}v&#|%k^qQ3s<~IV7gl{B`rJnu#lD-z?x5TE8;bGJB4g)!KD=84{zPYU zM!^8JRQ;~GXTrK(EvC`he2QI|bGLB(SxM2@frrN-KH^nr-eaRW-*?-OPyI+whPQe( z7|mBQy5nANJ~bJw9(x^{r&FjsP%%wv9tyT2Gz$*~akSLG#qBrrQ7^8Pe!daItXP=b z4_)ik;q7}%`X2w~>u72MYsG8nn$vG)4aMc>2cXw3RE^B{Iv{UQwx2`6-#t7Qt=o%X zGsaDB+4e>ww##9(p^x#@w|)h%VQ$=GXUmj5_EW2aeZkRiVyP2}M{bRi<%6gpx~yKy za92?Cl*_MwI#EIS3JUT-t?qUW*aQBJ%PfX#&>d3G=XXYg>4-Wl* zUr{1FD{lAALSb`JLRVh1mVZB<7nwbLlJJt0rZqqFZEyO4uV9*7fy3=yno;|zqSe4Y z?)5$nUaTP|#tl4PGLMAD&F4bPA9vDvKEgx!O`^5oGy$LX+qDx`VPj9;h|4)ysjMrA zu68ER;mni&4D+&NC>G&lSO0uuC7{ZraB{_6B#() zdC}XbQ$g*;#KIBtQ$Yl17_v%mVGlgjQw9drpWzyO86;XgcJB}=D4s2E-l&HDDz5y2 zNV`pdP*^zIR`~nou)q;&PJ(iVPLI=i-+HR@$DrY^6RV)hFKHE{F;VwME6X?)LkUbN z!ksdnMXVS9+{_+sVWn0VNspOkEDn)%kt$=Yv&D#R&A@nO{^H9GK53nZjP;=d$L6wX z!tUM3jNCNHLZyAvk|qANv>?f1E%@`XqwadlYIT`2AS}xH@{08bn44 zJFo+8D#&Zf<*9tNb+s!;`_|>WRMc)+?ZMWIO z(hHT+_bTf?s%bY3Y!9bB^kba&UxPN6Pu;_sFDI%u#)wuwb~C}{Ka3jQCk;@xz4suOdGz<0ibik78Es9LM}rDjDSsE|P#__F`vF4; zAZPOFX{0fu&%ZI*{kmMojpTpD1+dJYVny50ku7zLr_S{vu;w?miLaL{F7At#%aI2}} zr#3y;Q*#eX6SxALE0^SGr1o<@k{Plpb~!cePAiVzJiO*rg7pC+#M7?k@Y8Mjr)`v9AP<*9JKS|}mnsZ`dAwZ4u9SXGUn)gWw|6LumqqBpYU%y<^3f8~{ zBs$&9OF#q_s&qy(sDDSaE^lrb@b3RYq1I?PyLOt)3k}p`d2vT2oN02k#CR{lo#BQ_ zuZv6xUf-v(?xFSK*Bn3mgarK((4yp2qz{7pqY#4|A@);E9+`SlSYxUxCISho@F9Df z9gy2fQ*ay24qFB{n+1oSE)IO%z)Ze-)hUCmsXn#gfj0hHwW8UmN!lfRuc(`WJbS)k zuhLTnZHB4DzB8&DbdhGVACk@665z7Zk>A$IS9+FhezN?C^~?Kb%0udC*A1%`R?am49ru*l$ zhqRz=_Jiw>Ewk%1hc!*6-?_`)FWe#?OT-P(Q9`W`T3nX23ZjK|rhxk$c0lB9n ztcBcxF51-RLWTn1W1tvo**6mm^lV;#!iJbgp5_!*JPqDJti4%gz+)omBOGG*pfY$s zIksq2aoP-RVV4L`|5HFUd@5aaP>zB6@s?(y)8ql$@ry@`q zZI9Vlr#@CE*sO4~vf7W52x0-GaeQJDxMmlXro6xAsypD;eXD|H%!i+}o2e+vi*_#8 zq_*%QEKPb~bar`quRdc#JynSv1N@Qgs(r%&!$PTBCS`b*Fu%k9!K{v{$l%cf7d*W) zK|Wi>d-}5{eO8i`F;d%+c@%QMCC6!&z5jCm)v?O<*pq@(^zLL28eVrLhry`srwv@N#xwn_7yN!;TaCb{hj=tsDvc6aploAanmtMutl-O`-Shp%CL=0ciRYj0YTc7*EJC1!W z%QEHY#Wuu;tF*AdC|Kufu9s!~DBHkDfT<(K(>rp!uEk_Y|FmJ&#q8FPsA+urYCaHe zB^Lg7VWgewIqfv-?Ao_nPBN854CXkA;ov3M&(tsgJ_PBRv&Eb+a+Wtt8&j zxoP9^{4BxSKO`JCQb`_jn)U^PP(5TbSZ%DuP87J7ad7RSdIY^>t#~BSM!Jvg$rPvc z8;9B8D=G~gbILqHL-*Col1Hw8Z|ZF=SiNNP*~~yds35JqlJ?MQKO@M%wMbI4{6@rX zGazg#zD~Wp;iY`lD_xGgwW+r< z(4scBUWcD@(4s$;F0nB6DStTTVarA!P`sfJXhm|0s&RUa0=#OGk_ zdZyKI;1v%|FSzZ?QW=vslWXOJV5L!eH9fURiYTR|6Zh7K#9G>Al))6M)}k=)NM!xT_5 zFEY|gF4!Oqr{St2SeT&TDT*_iX`(OvQ8F6mfAGkwEEjM7Ta|ojtvXYiOui%nk#_&e zo2Le|xZiroyFs(|7z*EJEquN(ug)+szns?*rXst3Mxh4p(+BlVvf~Vty%#nl!)Sx? zUKwo{b&LW^!l2@;)nK`T%hxhe(lCOH?Hw|#P=Sg>wq#q2+~%rK`ypN(!@3C;TRnXj zi^m@8d1HRmCoh{)-m}rB_h)WY)<-pNq-A!7wkmcKMduF$+m2VF*$f&Lgg$NREfHzs zhj$NFE{_t;>9$3g5TmIzq?W7*5%y;Z_+8hY4qT}2y~B`}t*>S1HA`5AtE{{=PQ3;( zJ@LdEVoe%d4c_j|y_OfBQnBMfs=hhGt(3>ZMBwHe(#VD~A?kE6cGJ*q@+hayqNt#y z|Db#FZWxiPZCI-8`y=>p&*0wp6Fb5x5nD~Qi<3J;hzzqH{f_n>3dNZ)8^Pzr(aE5V4aY;@G~`-XOs`<|iOOgXcft_T zHA~H9v5zvxGBY8;G)(@O<3@Jw*&Yno=)k$VJjMNC-m~|*tDx)sc|g4L{AXtF>n``c zp}v}#-d-##Sxa=rxuH{+Bb<(vsL*r15TmBL-Kv~d{+}+3NaNVn}2aIJv&j4 zCdG7^786`~{XW;}@Kr(LDb^3tbUFBqce8YGH`Mf{-&PNG?C3QW52Ud8NZgRL{YGmL zyg2GgDq9g@1Mm5IBaCbNl|WcWA7s?}MP|v4i0a+|L4@sk((R`OS8?yLOG`G$tG*wK zBZE6l2W2F%LenvcCG|cJC&!*@SPzYQf5%#`I4jYDmq+Nlo9so8WyGjF_z*9F=o9VY z%GFVl?}*=UmmUc@9SYrVwK8bLS!g-w>)A9YR5LaVqK-RZzX9!8QmLDrcaZ9}l8*1f z3q2|X$L2kmW*!bnH{NmcI0wmOz6l_|eLlYz7c$lFStnwdT$cVM#?9-wBnIum_<%zw zmsP&eAf8EC@2iPtIi_gaBNa><)oB)-bQ zpqP5{u)$dTf>66h?JFaj%wosQ+NU7Zx>2_z<%Rt~Rx70bKr?@?;U~&;n%TEDIf$S~ zq=^!dv~#e&Sng`~lfr5AdmnnzGB&wo6|nTbt3P&SKs5gx{xh7aD~}U!N_CyQk^hy9!IP8s5N8H@?l9(vsTiyN0fU zLGa9TE@}wJ25bJu@-;PH{gWCM!EeU8Y>!`gy!eg4f&c;=rwB0dzN><`^RVYb;o_(3 zzH|e&4-YOw`JBTA4c5C23J?|kRmz1gx%t6GxRs%G3OXb`9?f(yjjwe8oI)OjS>|>% z^(c|*r;!E~2E%qQF@FGvy2g=0&HkM$E8RfD0z_0*jx&0StmGEz?=LSCs7RrT=$Bg6 z69fn9dZwB-Nf@eK>R_fZ~_O#!)v5@!?c!9DUll~XM3Ik^FXuGTKp}&wMNoVVO(hiaHd8so)$=t zQvQ3TafOJ@AfkODOx=NFS%#y#7Own$*-d=3ec;fntDh)fPAUL%^1}*i3ePO8J~OVd zNL!$-n;xTRsi8M^E}#0#WoRki+vPj^+yTT$^OprX?2K}DLFX;HC?d)~-m>fNm=tvu zUm3m4TbTTG0Y#IxV6_i+k~*j&kFyQOx8K5ihX?IBYDT~Ha*5=-Op?$LW0MSNbs>2N zt(hnvE;kRHqdQKJ#owVJOSFaN2TOwX<=e`TR0AtrXN-!-#_pI#D%ItFllP;9h$vev ziQcXu2u(QauQbDf)VZh|MJh3-Vals$u--zm^X()MkH1O+IK{8=rrGo;EKpMSK-^JA z#1j|3;;7WxP1D9G^|CKFZ>J$P$4MteF=Oxrp?4BJwTX_}L>!|HxwC*K*ykb`BL&qb zb{y-pas^Lt_FwP6(;nI8GM#Y0uZnw2mP=-cWt-ymOlt!UO+CbjJMIUNb9pq9=Be?5HJiX^l^RE0HN3+JqkD+zRR&RH zBW8gopld*|XUVIGbG}W9%&I~uUlpc-I^P|dVXkv+9NO2|WvT|jH17R4{EKfd%D!nU ztEn(`tllD6gmM)s*SFSwQdMWZ`n)WoV5Q@WTzq2-)OIFUl)>ghov>UjX7d!Rd$F6ctZ`Ymz&zyvU-h6<^YzEYw!Gz!sc(FdNlWpIZ;%g;wP&!Z$mvi2 z6~z2Pgs#vq>9qKEVYd*|hn_u%T!}>{SL<%7(cx8Gu6q^M24m_WI|5C${z;jwdP?{H zWH>7zQ;w@8rfyoioUmMN9cHyMlyOPD!#h)@L7q3e0%jy%hfg&V+@lY{k`U=JvVZgK z9#vhjrl!vZNP9bg20~<482x zdM*9ObgA_jx0a*}A!Ga}9|wI3lCyi>6Um%PzZu3=f-lFycSrX_A-;*fD&>zi^LbeM z<5^`?UCPMJ3zJUAmDbhKMV>L99Tow-QM7<-B91KyGPR%MXf5y>zJh+!oRwxM-?5Ui zkm~?5#QY2l)lDxGW&?-hDVJT!^bHNv@fjfeThxMhdrmYON6#s^?Oz} z4yq*$g`&L-h3^ax^7I>@+*kGzBHbpoeVIFQxr#qOb}EMr2V0Why+iEx6lY)b80f&1(RoM&d*)188mj3iZVmaV16_eTe3vK! z%Ck=5_3g%QAguIn4W(TznE2f=nao!c%vUC)Q(I>t5%YPA%g?-&`KD;^wQUbKvyD&8dqDEG%JG zm$ZjQyedm$v~9M$U7X`iku29KoCVsV6H!p>U*p=5f_1xm;6{4^_b#EB;sTceIeAAL zZX@_)8_xnMMrm1~A?}uGEG?SLlb&=i?2&nlYsIaLi`+(dr0dh;*0#RYPm0hK8C3gZmh z+&YcHmX@C1S*P&7<1X;+p1Ad@DZN1(*}54d5ILS?5l3B47lClpFNmJ`9px9|83(aS z%Jrdcri-}l7rhw3a?5}{XU!dvhu!Wrf)BS)EY6(CJ-YHDZE%kCE^=29X98I|=Pclh z^1hIe0;l1(!I7ZZ<{ORD_gL2zmK^*-Gg5D)3YwC$#>I45buctPT`ge(oWTh8c; zaqUX z`>$S17rEwVviXmHkwv4921({eKe<@>-+uUi`R7Y1z&}3H^v6XC7%bs`^%ubBAk--w zKQsD&4CsFjH|7zT7Y=j7S&x$c`M>}3yU4PU&?4>RC) zFpq~+ivRNI|HbSmkjF~C^^kV|KGXc)3{Zf~9Y{kEJ0R`9`t)zn+z|l^RlSI5aCV^O z-&E@HtMT;0QNm64-$cT{OPS0ZNaZ=ZNEr9kYu79$tH0&xgGlrH-4_EPQ*dbtW?J$& znfKW;Io&a-7<~@MLUY`!A~gVav~yXls(iKbC;q=!%RMFm-(hP^H3F2<@uCQBt3}>5 z8=njn*hlpLp(vtQKiG^yPY%mYm92(N-R|4YKlnI9wfAx(CpPv4oqU?4l$77-$xh*t z!uwKrt>mD16y4@1*1!5C&-%ayo zWPOd-E$`Hn6!^|Fr`NAvKZJz9|9y3_*j++H2}@RtOuE!hX4KWfUYt&lo;;|4VsF(Z z%OvL6??WAaeIor{HwDu}ZQoQ?Rb@YVGSkFi zx3iqjtkcN;{VFn4T_=0|Y~0Fm&T1?3^dK{o*RJ4Xx$VSL1BT9rObzOR5qdN;QLaYb zBi>y*Jz47;-0sPAWThMwBL8>w`0#wZ(CM%+-|_gsP_b;gS9vhs5WfQYRv?PUMtXP5 zsmyV0*HL2Zc-2Y>y4S4B7Yj3+^DdtKy~uZDG+M(smGbobN`JXB&6lh>WGX2sT@S*@ zO?BJ|h)OChK2mC*h_D(Z&|w@tzYjqGim^9|<9NKJzC@?K-G4`>X{nl!H}N|8dV2frMiZ0z zVa&+d!{2?4K+PT;fsm7we0+yEI4UX=4(Cc&D>)e4SwM$Opr*FdWfnhFzf@l8a5$|T zvKDE#+JV7T?5mL<$92Ah)#5+X(nQAq`}yjIeIH^p-iwIcpz6!54U$cyk$olyCFEiJiHY^e z2W_Ua^>uYk1yiX?6z@%f9rrr^3`~dl7XZK7Gp5R?KNMh89V5#lLMk;G4VwKJ`<}c2 zVt)!F^l*5N&&o)yzqhy7&_$g+bKOdId>Cd%E)LX;z*MtoUy9uO+z@2ScTX!{2T*xE z9WBfWUkf)Ok{^3x=HTE!-gnjr_am+bB}^k;nk=HH(Nrs}juxuL%5i?Q|F?>OMjT4z z?^$8lR@ph>8R-gZ%ABk79kE*aN8V$=9@Uivy%}nc^f)ehKtIRWLn*aSZP=H89=10% z^rZ)UuL-xsn0xlZ$rQ%Jql3P(jBFQEcCppcL*tUIP7!wXjq~zarV zKfo13BSw)4Zx_YEam&NWQ_-fQ^!gwg-aRoAlxf?GRs+2w9Gzw1G*SabtdqI1ZJbbJcXhUZ|(D-8Z3R+{`Y~Om*9Zc#bJgmdVA`Om8#{ygcqamn+w5(-dKZpGD^V0A{d;r2}3 z<{#J#RK;M;U}?@Ogj*+vYfNN)?Yd(Xcaidi;0upvbdk$(hebLbEbQ$RmXU;+l-dki zPkCkQb;Pu?>DSLJSQSrHxe3`0FXKW~I^GH}-g<1&%#3}mAg8#(K88#)QY&l4o8sX> zW*vzVQTJF4WQ&h?hE7MmL4Ydl`8bP1#ms5)%)Pmn(sCy=osJC$$cKy(E0e2;HAXvb zqCeVp@qj&J89>J-0@jFY{^xUD*p`bixp?7-rE)a6X#9wTG(K$WQGt0^)VFh8)l+d9 z$knZ*3VSczOD-p)z&KJ})~9C2DyR$NKizM0Wm?RHFQ!zsV8@5I7!?dqt(KjhNXzHn zK3^7T6dGrz-1VIrHuQuV-`U4i-2)IVR^NOb=gJuOsy_aoh~c2E7_<#n?w=TN5nu zSAj2=-g9_tfg!H?scX$TUL0N@NUP0@v{j&43v2b#@CIB&@!=}M6j+_mSgFI*=ey!x zK?uZS+6len!btlwK;=r*9*#HSXroE%Xm1_Y!kg|soDo_>sD@OAf7!iDBWlV56-0&E zB1j}U8{F)Gb01f_I89A$4BT4EY`NTT4QwryFYf8+T%=uwah=lkrIqtvH)nR);^=8% z8%j$9R`!yHKG?BsZ?Laao(Ey9emcYCL}L#LxSz}g>O^yV%$Cv%y|3N3{t1qkoPRys zy}a~rl}IL0Jl(p8*KWtN3X`A5oBw1_!7x3acGTw%X%R`*d5;~Ez@Z;Y^+*d z*+_1$6OMNo_VmYA(!eW+=H)uuCpgq+1G1oftWoaVZ?{%L#|Ia>Z$nXfvYjb(!)FBA z#DKe|t8cOg%)J&{h!~s5C{Ic>^l5U8vkKQM)#;#}kQ^uE(&(AH$Vl+!FM~m7MY5Zy zgpj@Vr-@c4sZ7`s-3$M(IKCP6<<4m&!8_ zA_CrO;>yURHm4esQeM)p`CQYf+L~A&KBX>y{r7GBr}kT`BZ!2b+R5UcP|Pm3B{h$lArE1df^@K&y+?srj^&z%L1F|IfCoO040T}hSqkux$Z zV$o^-iu5<>g0uf_9=O*%i8-Gz7L9+rQLtDQPs@u-p(@Yu{%vI&jxBl*c=E?Tp z?3=aG=~uE;4i0%8q8$zv66@|t@JRJ$E5cxCKo#?!TQhs*SbWIdE19u(&vfg}R3**u zF&Fy*|585X!+&3WuM*#&Q!GQ_ef!U6u30J>S1)Cjo!EwhKx+!ry7q9bOx^yGT#5Kt z8_&_ND!G-a+B4tuQwmk7ROHc#;t`iu?4HB=QjoSAF;rMIj4gfkh4@<-aPW2Cs3Y$I zi&SgbHE~0|-tFe>tKtyuM(O=fh{O2X$I*ZH(YI(Mm$HT{T`{Kc%k~5x5bt)&NU+9z z`-D_qms$`O#>Hho5z@L{6H%M)!PWw^ZfkfYEPea*ecADjYu2zg_o~8@D*n!HEs+WR z?K)&IWzF<+TpKiN=k#;OdXRdDTyjM z34_`3cgN$SCG}JH{mnV*CoH;LHj#km&Z6o6OfRvgj<3n_+N$krbpR7fIj zx;_7ks{jm#Q>BN)c!#dVJmAmT4 zix82KYTMtUfa4Sa*DwXrqBqO%r3}-xlHDMCPm_{u`S1^w=pBV7V?Q3heSW<@P*hj& z%pJ9Nqa;ssOg98*Au&qTZEkuso0-6b`6is~j!RKK69y26lub%3fJHKxjydesj8}YW8tiTS zJyP4dKbW;%-6VYaXs2Jx2V@>69jg;1VDP4s->C5_O_4$Dg9<_#?`$PpG8lZJBp}*C z)3PdWs1jAqqdzSID;E)7K4LXi@&OW%1)j0op8b7bgaSV~h}lgit8=PM)7|#snH*>w zcM)T_e6ju7!KzA3JCPT1ZpT7d@K^@nzuFaF?OtknffAyQ2Y}YU08{0!qei3uJUBM?w zK9pZJ1#v^D%<=dQR|1Z&NQ5;AE=R&Xs(%2FG>38ZS8UVH*VHvihUsXZFS$@*WBI3U z-VLdQPStwR4Of&ry}f-mYVYN8ZW~`mx^khV6)ei(X06;_j7ex6|gSDu8>a<6bMi zyKvGLWGA4kR=CYVqNlv6JgeB6IHRPul(-ZN1Adkd>^43PF3)LVRGueh*J=JS4?vsX zCy}=>52jKMD$yTUW^=9SdZcU@L4;75j8{CLlDKeZ(2#vcgP8X+$|*S+#V$X^Hs@5q zkTIQk5CZr$Lq}%-M~#*dYo)AXnIy=}=3hqVlJV#laDg~n!No`yNaP3>09yaRwbc~3 zAjg&+ce5AVES&Pa`N~87(fF_7}O~Bde@br`mg2 zF+_j}W#MX6P?$Z}f#O1rY)&pA$;!~qkqSS_DZ%#K+!(u!<#hXKPD227oe4<7*iNFd z;fgfGNLW=l#|Xf^xCM7Ez+e`1WE7CX#DtYA%7kxWNEZT75bg-V$^?-FyRggON-EHR zQg`3({Sh!sMw?@A`Ly5hyVJiOh z+8y>$--OL97CYuXbtn^>Iv&dkY8y!DJqf}|S zlz}jA*)bFXfiV#o7$bwleNuYga*j-MQ5K^7p33>E&ddIkSDjvDCGH~}-z__JIQr!V zE_^pHl{g$kx`Nz+yQry`m+-@*J|gM_1Wz(l_Nsz1CVqj1!gbs#YUi%jwq zh}{NZ(e);6@YhOAhfy?X^lnCS?vSq*H^h2y!o+lqd=kct(2+3z0g=TGRvy z{RGgwu4jhQA{_=8k0}r#zjZex$aeuOPpoVV(@wY4M0XlAl7Z_$Hv1&No-_=NC(VZM|>CDp+jTtyu?Y_aE06qmW5YW ze(Pnnz>Q?cU0;zXgy%ixhn=zGOt5MHFNeeNS|lRqSdZiY*q4qcd{<(?)wDp>M@BvH z_HWKWK=p=fr(lNSnno$G+^M`SagT0-_;7uIIlgkQ7R82(rHP!cS9i1koY@JW*JKWg zzFgfl4#37tBJ;icUZvFALig4yu8~%Mr;(Wi?$;Zl?vS6NWe<`zEf8-~3`p6|bBq>R zU*k8T$VG2&iU?A*9N^d+|D@IYgSjIWk_lxmRwxZUa6LnTtXw10 zjgvV~{;u;1^peK-u%K4c7Tar^0KQ{m@@`2En|Fz2*WfABTY?^lNZM$D|F@v}Q35Uf zl=b5SC-13$>#8HpH(O{=k8orgmWGZZ&0xAP{C_BW@H znL}0!CBkJ;z83mT6W+fb62`rPN$toMCz7JsAo z9NrApz5%ol36d5%Qdt9$$#i$bO6W#YV5g!uJB+G~?55AZVhNa=0i!QpRs@d?)a_7g zqG+o=3#>_xIpIQhY+b3kx4N#$OUt6`)mNcXR;6Kn0SMCp@|lBzQ)5$ ztYn3aw5c!QHseSp>2nhyD_OAkE0M(U?rf@K<9>wIT28BIS_?8b+^ISr zrq7o|2KtV7$4G%N#As5L+|FL}w4@v`%&{h8r6ga#4dWBeS8hKt_a6FCbt`PN`Vu-; zk~pyA#Un!FrL6~>s#YU%dp~UsR|-uw_hjI=1|4AocT#ha~$XT}1U7LDde zUIf+~eBY%f!LBZMlHP!Mr0fwoO#$70WiT-U&kZ+*dN~<;{SFG}KqaWO+_a7ae=f@D zWb!#f#8jtNmF@OozI7@73PxOAwkpW8n1Q>jbQ@wYTm`Vl6r_;_#oNEv#LR^{()uAE zVB&-p35RTz9JYI==3{-lwY)j0q$M-x#4+&bzZz!1s9FJo`h!JR9DxdetUKUO3lPI7 z=K&uVbrftWJTE^2kw{guh=#aut@N-K$pr&lUcb{+43cXBT@P$ zs35ioK;at^Gi-x;vB-3)<}l~Mx##m08qcn~@4-;euW2f5?8Vyq)sI}LR!WEj7fDG+ ze$vaLU9gHY|5WbdxD{(X;ff!`aj@0D4@ecuZ#L&FfJ?^1U%+n&0snO40Sw3caMh|z z*;>WUmM{{Tt@d1>r+|2=-8By5Y8tVbi}0(20>@Ke3>CBXzV$nuJ=d%h{Jq1mQ?R%#P!Z=!xaB>F<$SWN@f@CJ;mGt9#Q?1oM3IJx& zVzC>j99S)YS*fqyB9yHRl0RpBTF60|J*vQTl$;ml26jG6@WT%PG<*QiEKCWBQP0=q zuQ|cRPkyeW-nW_dn;$E4+FBmSUB6v=+sAsM(iORv@`Ke-Ud6ma(8Buj?SIKsKfW-0{^`h6n~lVT;t>a0RpC*4*&oF literal 0 HcmV?d00001 diff --git a/Help/attachments/PbindFx/PbindFx_graph_3a.png b/Help/attachments/PbindFx/PbindFx_graph_3a.png new file mode 100644 index 0000000000000000000000000000000000000000..2ab825ee24d4a3e7cc94c23b30bf8de12ad3cfcb GIT binary patch literal 135925 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�AnRcg{{1!#=rK6 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%0D|9dN9VAO^bn;cG$|iV0-r}qOb+eC-;C{6{U4qn{ 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 literal 0 HcmV?d00001 diff --git a/Help/attachments/PbindFx/PbindFx_graph_4a.png b/Help/attachments/PbindFx/PbindFx_graph_4a.png new file mode 100644 index 0000000000000000000000000000000000000000..3477ab6f8e45a9037875c11a5b5fb83b3d40ad49 GIT binary patch literal 254391 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%0DLPGrN%njjvJ+$C}!wN|le-5m7uv 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%0AeYejF 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

    @v(%YHxM;2Zr9A>Jn zu6|jsHbv5h1u%^fhE3DDB6>UPQJ|5Ti(uEhOzk$9r*$wHU8gi(O}}_xu7Ge343IDB zFZ%vq#7j~wPC56`vqfHAx73(=WWW9R;-QB!PSxzu;S2B*mQCsVON-!?H{t3Z_n)7> zW=d_L?FSMuVch^ud3Jjp9okwhXC223g>LksNBXuHo0z*?0Jm=Um#<&B`II@Px5V%0 z;Mw66`6l8}`m&P7w{MdG{Qq^@WjlX5p=pe~`*pAORa)xq{J5NqX2hi_LuQg{zFs_N zTy=GKudH+VbFk9B+0psowJ(z?9F2PjEn?;a>u7hl#~`7$aUDj$;tWlp4m1lb`81Ro8klI{GrPvrufI~ z4e5PHVL&Kgv59-y^YzXGx>+X4y_HH2LLqHI3dc&9H}NRCurt$IH_x$IV9S>35+Rm~ z^_Pk@gwwfDv_0@izx^?C>gf`RQ4Nv5%2>z0ImtG(QyH^_ z%%UKUe0NiXxs^Fa-51jCK64+?jXEbZGAD2*JaB*UPoV8SorpV#m+m7ZcVB+Xqj(_JkpV`Ov#^y0S190T;=n# zLhhqGohengd;ke?skHSZU>=>F;r+~Dz=OLZlN`cm%{ z+4r30sw4EHuC6ZDx<@lRpGI*P3_V?<@?%Bv4y`|b473V)yn8pCytYA!1Vfm}=`Bd> zwJ6!N1K46>jZ`S%Ptg`(;o%H6)Cp_y?scOs{FAX>ioa8j>h@Z$Qt@0JM=c%BZWn6M zA$zwiP!P~Iv}R@6pV;rhLd$N_UWwH?mY|NUTztH{&a`Bfwm~lsj)o|7wnOA``&QBu z!2%eJ)rkM1fab%1{F^>F1u%B7SfyAZ#dZnFs{W2wDrxTCO*PTc*Lp~zdR7hJw)vIo zMF?pa*+>Yn0RcA{iL?uw$j09EtH*nyJ3p_qH$mU}k1U6l}E< z)&FXq?j;YmxK5}h(MpJicZpjikVQgxfN2T2euYd3xNj%KOaFLH6+mEOu&B{RfA1CB zAB!=mK33dXj6we2fn6=fl zRxCmHN{(wBX3!;sTU+=|bQ@=f{0pr$tk%{0Ic4XN>4&N1Zf_L7?Uzi&Wo~4$tk0?2 z#{8XosbsJV34D%^Z-jjZ5sH)vTSP^3gX0wbd7g_%_@taq)3lM+N>oq_nlfz-2s0L8 zuzZ-qbm~gOVTPJDz3;Q`n9S<@DpLdtoP4855gOMw6UQr5|a^?2xQ0w)krnN zqanmOLNbM>Op`YTeo`AcZK$v^y|;~xVxBG#CR&~}I8o>-MRp1vn*xu$e7#W-c^ihr zfR8e%M=Ar!wBrN)r60fVJx=e_yx+vEMsE{CtT>6(ZBINSz^yva?}+$fixS%vm#Q5g z|9>uy$Qt6+?7fG$XeSYw@~dK)%Wg%pSTAOEw*ozl0 z*c+`K=R1F&NrJhn+?|LUKt9F%ebpw_D&s6d-9h3)+pgXG@pjp^wzg#Is@QKYkSm4} z%uQ>w{{LU%6+=^>9N|gjKXQfEoIY?GjtK7b znh%PdGKjB3#&gD)SB`!-u3URiI_ap-mFJ2P9=FNJkS+=TiEEZA9R|?In&aq`0Y%}% zA^(ifkKOv>@}CT}_4!0_KPy7=0x6(ra4)cfv~FIf`V1YlMGUR;WCzi)>v|zS}Wqg`FHpxxNz>kGF^Vyb=8xOwn<`)IQIB19^X;@vvQBud#vMjpeM~8pA{Jy z`+v`BrrW&(a15gHlH3ywJaZfEv|-;X58*1e#|~R=kVYZIK{C{zrBk|?+rAk!QT>i9 zfq~(5b=vxBl5SY3F?!NDqFoLc5|U`qLe4cXledqKsQoCOGh|$r#AxcuKJatFBw>xU zXj5h~|K5;kcj&84Wch*$zs^@U{8f>T+e#(}8s!g2iXgE4Cvj*K44wfOq~W#JqPf?@ zWmW!uPLjtOXt#Y)H96F^v~Zuc{xV)g@9h<_n!LN$bt=aoGd2oRqGf9!-pfKV>O}i1m%$(JHf` zK$hqlzeV|JeE@_pfm@$dX2xpfuA51gC{?lckLuyDUcdsX5zSe=k6GCy9KT1KMnGDdQ> zgjU6R>4Tlf(lB8iis=1?p2+!2pa(c)C)FwXGrSyG$ zec`3878vOj92~rAsq*MbYQXA!G5j4!pFbWS*>pM6f|GM@86G}b;Pc@8;I|L-$QNpn(^Uq^|! zWiFPqWDeuAG)MFNxiZ(E$W8o^O`>6Y?W100O;~KKlOWf;UtwAYx5DshUnAPVlyXaY z6%`dCQ2bEjk$LLbM1=2gDJec2r>9T%6r!0RHj`hBK49Umms~UNcCgUuc}n?f?7^dv z-iA};5f$_(HnK+>7VP~K6tORBc(tIeYi)v4L%e2Wq{`xcr=nFJ6!Uo`tv|svCU!cQvW2zIAn} zV>DRq$SuO&!&j%GtykH{uRTltfhAaW!{eM>MhqA_g0O>MDb=qz2q*wJmn&SpMwDC2 ziR>&~J3U!}3cf}a^7^{y0}VI(aiK@tBg?kRi`mrPt4;qs5Rlk zx8{Aa5P9qBM6Hgww>F*NmX2-x*9aT(VL%0##x$|IVBglfDCxiVyU*K@; z=HEK!9(32Bk_%CbC?yAd2ircbbqCD?f0Zv>flU8{X=7_A`$H+MZ(tz~-}Im6Ki$wP zH}`vsux(o@pJ`o3N;gxQts(O4rVR6$+LGuvw`#!%2il)7x=kS}d@#EYEZdjkM#RVc zWnTZ#Pu4?-DD-3lr~#~GSh$UijYB?R`7*fWHdh5ux>>Gc!pjpnkg7ucQR04_sG^1Y zfB-{M)6ch|0$$P7?i!k!ZyodGSkF(bX zrn)(fu4UuDG;CbGD_ttLS6pFS3tnU1aBSS^v5U>whsN&aob(y<(Z8kMTj=Un za;eVLK~-4FC}Hx>%*6Vr9d1``Y`WJyt{Jj(IxEoTe`&NZ zIWzZqhJB>+Sc+A9s{DY^5 zvV1a&{>MdskdugHb;|gfYxEI??UY}c+r(+=V z;Pc1_x$G$|&V#CwYI$98H{VBYuky?vk+KSMTbDZwhOo5A&R5cZbOg5hov(ZK>3HE? z_FucivRq32vJiH!d}Oj1BT~LJL((Frd52S2?25n3<7Y`}BDiF|yt_KACZ+8vF4i`0 z;*tMTBxOVSR4d^3+~|Y8Q&#w$hL7j$r+Y%IhVArj4R6x4y*Zug^e5&Z)n*sB#3Ns| zsU)RjmTKKFo=3lvzb$b~e%SP^v*Z_&YAuH}OCy8h@uVBG^M9wb45iWM`?MpoFP)yi z`m0y3cF5bHpkPiq_xBa3p|U$Y0=6@8Z{QlYoBi}~ASmj{HifkbMp1E3I?lNlX6&3f%m3jPbs}?!K zv-HCwNfqy;(DwnR8tZS1_BHlY9e%$>>-+nY!6*=_QZRe8`3s|zm~ZS--q_BD0GpeG zqFa`Do(|oyb`|X2_hXw;%w2$~Z~o^kLKx2YQZ9rz^)4aaE8q?zK^@7RET_bPsWiP# zjM;GFbWyRN)xFi+e?(J#nlFEM&s;c_U;VPRS;}7XYN(H-!8<+;ixwT#7i!+dSN0m- zpLV`isaUJyA@)kMPh8A5Psa7oZH11)d$z_dQim#J3uSh_JhS(Eufx#~8!RW6o-uzJ z_({S`&P*y}gm23+t@wtxI}x|l+QZjMOs$NOG+*@m$&RzG$0Y~ee@{~%8F~Fniyc9m zUE0td^*v97mASbn(diSt!dC@>xkR=6C~Az@9SNhPvU_-|9IbzXHXRT%u8iq8{q@EH zuX_RyxZ5-jynJq2^-=Z9ld)SH^h!miEGjMSOLk~4N{*K3=4_j=D4gxu%=|G(_p_sh zgy$*k>O)mQbt*@aY&|)VP+M3?I7~-Mq`xRjGMtPpFfPdeYJ}KIz(AJO_sd zIkR#u+G+mf^c0=`a&9dB!U5mgFKX^R0SoWZK+QM)-Bg-KKShM|sSODPmJ2w?fcB*z zI8e>~4e9>X?`u{sxN>m$#FILWtJ{uO*GZJh`1TAeW*nYi_-e*^g>6l3?AA?ooIlkA zf3ubAg{(PYxgkB(f9HtG@L7%$%jJTr#C>1tMtrtkWAP<_wOQ1gKUFMA7{Kusu->X2 z-DL_GgOq0GH;?BrWD=49x7Q?5hZtp-19?>O-OyP0<;$0(L(eYCo6!p#zwGWms(UX>A2?`#sI&JS{TrHCu)yp%Y&D>}cTE9zT*{=M<1vMvK_y|$O${{FQpp>=qG4iw?TwFZ4C%W)+RH4s)^ka}WZ&1dveC zR%NAsE`ICJ%>%r#g~K8#M6mPi zJB2rA+SMG&^WK#$6RwI8dHLkqbB(eG4XGk0+rE8n%zESZ>)n8~eaG8zMdb%YZb@r@ zymfPaPj|yrL1Ufx`^QqtwP*78{VZFk=a}QRP9$fDC_;C7Mm?Sj(AH@E1=`Bb;Topw z`{=maFf`w?$V{F0A^nTt?n@^*^TmJh9JM+;6+P4gstA@%y{hbXQN!=ySW5%XfR5yn336OxE}(hp1_M32%fkqrhAy z&PO4Xrrz>;QF0us=_@$vUBrG>%UFI%d?}ySb98l2P3Y<)*OGR(3Eb<7Q4-Mf7UX)B zsDH&k;MniK!RgYLm(zcxeo|rt&duJXvnCzJ^@#(eE z>kU}O^oqPrthjaeH4~6Yf4nj%HnTjovo3dqZ_#uq^TVSXLl#T#@%82j(Gc5JT*7~_ zy+%s>=jUBAYn6gjgC$=NM5ZmRuKRE(I4kzk?-Rkdu5>3=zYe=~o?jZL>xGk<&( zm#uZEw0?6fPuhRYq41u5(s`4o9U04eX4Q6ldmoy> z|M$~{^i$_Htuh07E@mV67iJiKow#jr{PhkZPKE9_98*>!Ze4}6fqaOpR{W~J{hviC z-Za*9XCaw%-t9j-b>|zW`4(Ktuo>*Y`kJpH&n;h_*&N>XU|Ep8zohY^LS1d)@0yWA zY06xp+k{2laK3TPS*GVG&#zNH9W24ST>6jt+V_>xD=Md1t`%tnTllQKx#Q|0+hTsX zlYb({SEU|_ig14yQZ*=LubaKSckAT6#og2Wu6l+_g268Ymxd22%4m z%3ydE|Jp3i#yZFuG_=zLnkk_cgPLf3P zQ!zr>(f>mcP>f{9{oiJ?9P7@CNj=ufy`lPMDy7HXKDzGym5}E=x5dLUgcMaHd9}iB z*{+v-d)(Kw#G!9wyf(Y1YvqUFC#G*LD&o$|=BNjs=rfZ_JHmFw-#h$tX{28M@{SaV z(GI^_+Z|9-Jht5>_g7*Aha zGFJOXY&Pt7rb*2giSQbyn`4^7`due+SXOntz7}3vS6Sk7v$Ck&@CaK>?W4VwnkHYa z?R;>U%lw4jWTZrfq{uTz$~TY*wuuB!&ASB6a!>z6_ti_{Xt4leQCNC=Esaa-``&$i zGy2Gdc@^(_%M%56ujQUxDROJ2-+0G~-YnaT=f{f%SbsHtIQ(KlOMBto>T^Yo$JeZ1 z^ zS7ILiI!=u9|FQR$VO6eO+o-ZYF;GH8KoF2_C6tg*kw&B&L^>rE0RaQ0bApthbT>$& z(%oIsAfX5%NPOd-bGp|1Jp0@G*ZXT9>z`BRyyLpYHS!$i7=GJH+(I#+#t66-JpZiY zaulWhVZY9F=tQJNXah1{876nFe9z0)DeIXj`s4kt;Zz@t#*g1HLswlr4ns7qs!)rPp56ekQjkvdp(#>RwQy;>A18O`KoY#pt#Rru=ap3OT;5(K`rU8?-ZPB zgFMury%d?>ghWz}#c4Mj0WikN%7rj%f+kWxSco=>QV?PUKu7_OPc4%H0Xai1(Q@v) z^|XGc1ta%Nwneqk8MfbjX=6H_rp4id(PQB(q1VbQ>RzBCdqg`w)6pfjTmLmK%4MU$ zOrl3Yo5<6$sJ|u^RlQ4F)6Tkamy0b&rFcb&DZv5Cn+T&V0D+38DWoyb5qy`p~#`Ns#VC$Zt~f55*y!;sbnf&&+{%;lf{6s@<~j{P#zlk8+o)cVR=J(shh z8hGF+)`Vj@$Q}4)Ume`rZHGl#H|?XQwc96_DB$V%@b!Q}Nb>1JywGJ$(UlCxs552C z(7pu>Z3s4gVuo7t1dXfC^%EG&fR7-(kMdsNMUpxXGdw#YuNWsNq#;S;xE3P%{Sht) zW#xe16fx{~MMb)Hn-x-Js?sB*#U$xhlyA}XWh|(G`=Ae6!5-J^#YHcSi*Z; z0Jj!rSU^)#nn%<^L9UqH0WrCSz15>npKny1oo9}2a-MH}Q}C+!nOoQrzl21J>j2c^ z>uneLEOiZ(oF9};T?~^PJ3qc()b~_Z^l*>I9;<8g!2Hd;dV^kZ6juUeSJ|{L8*5E> zQ7xO-Sk|`OMq`V6sh;tM+_v+LCFf3qUO95jp@A4B0f9A<#SnuA@%AU4c|j^g}55ER1p$ zdPWLy`CDi2GeXpIgPn@boviBhnsdcc$P{Sa`o}gJH_Us->EF)?8tsoWRCF!}aXlU9 za1d$vCLu1a?v3jFYn;Zu>s`-%bi5{sIP7)YJtyE33|m7`bTC$G&|(T^=VhSY)_F1H zdDL578NMOueRkdELvFwv_3e_7-|dDxIa6(8!ZQytqn(yawdNKBJwi#1V?&Lj^Zkzt zomU7BVU+D6c6BBeT^&)r%-g7MX{l*)?K&5# z@>(pPeP^M9k&i(t_e}L$cT(DMYHoe!t$|l;1f#?g8*1bvmcN>ucy5hMY!+ED^Sb6d z^6;2YS?YEvGEaGNCNfH7#;b`TQio18b9oL(Rs^wDmJZ)6yb){o(Y^=i=XJ@e{q=UON3c9Za+PZ+p6jcc zQLAh2nNZ#^W3^NY9^>gMJr40!3PGuyowS^$iKuaZ^1 zsJf4(QeU0hlb4bS7^cS@7*u>`p*B}=xR70N{|7~Lvm9yR=VFx;47qiiI!o*AD;FQ# zFALRH=t?t+)2qsH?aN%5Fj8yHapWBDq>3w$#-Q575)cq?ct`>joLA3Vc#bt161Q)g ztw(-Q6dZNRyzb$3n&$*(9phHmg&Mie9TZE3vZ(q8hW5wi$_?5D_HLJ!42s6s-UsYC zC`atQlYaJwx2o>?tjwM0T^766>DHkn_NeRJ4Tft|t!k+XRM`saTfhAovgiNAzBTxH zuLAWoSkUO2sc_FVG9dD?NnQTZ*+Qm)GA?(PrmoH`_Mp_rEp{D7*)a@<<{K1#zdSge zmo{qjrCK%A=!sT@xti?RV|O*!+4QR04H|-zr=QV0{3TmE1hB{>Fo<1m)fW}$4Oqr z{N!ED9xfQ&O#do=Th_(pi?}BD$4dW#0@n@pD=xlSldAN#XO|MF+D`o3PKO%81D^>&-M_Xw>NuuagLv#cN0fsRsj6!$wSUTYtKWFZ=#^Q~ZS9=QnS)Q$9GT(}t-Q zgPi+W+=oI}MsG0L-MnP3BIwt-&bvG&E5|f!lpAh6N3B81`TbS{c-Lj2Z(|n|f7VOe z?_L}(%9UaaTITBB%F1@W<{rPBhN32Yz`aI2_d}eHE&fz_{0$K^MhSFCNTc`;M^)$W znO(t6%Oo_g-7A6EY$)&Dz!EQ@m#+e^a>CX3g-2NxKj`yk{k{{?8P9dfK0@}6+D^qv z+S|G^ezUdVo%3b+pPh&)Nm&MNUO#G~g!EHcM$prL2)x?+!QS3J2{O490#X?4lV=s~ zFCp)$2EPI1pp=jxGsufZviK$DZ_?1o|a!@6DM3a2%$d(QzK8 zg}rb-o~bsMTQ*{5gs$x5p^hA;7WO~vM&2GO-+P(m=shJ&!+|)v-$n}>3X6UOW2?(T zP=?9xHS1PGzHEZHbNmLpWL`%|^9tNrS{CklI>(z}%8Ulgu!_MiF+E+?g!q661y{w4 z)OgM>29v29J)yCq1KH||`zasMFB=Wl$_L~11->b)#tki7GHRK%RnLCZTxf# zCcdRfK-zrz9-^CyfMT}%P$uVheY=a{CjL=enEFbvxqK|NGbaes28J}s9;FiUC$>g> zNGtY)-}N$aCcx@JM7jMY1q419532Zys!299nwbyb1Rx9ZUse&^>@0*wROQSrD8uu( zj-n)4ZfhE5=QYtgM3|-m+l6YmiwHGv-$9Q^+PL&Mm+c5CB3M=o!SV6A{d#QiLYM`E zA9)=igkH5H&&5cPD=?jc9u27q*K+-dA~qU8Oby+cLegDnm*QGm76KJ^k}!Q~Funoa z{1bB*l92=qhFY}-5zK3+e3nC-z+zzBFoAe;nx~pE&U#)vy!h_`atte zM^T3rT5&ea9RPdh*%3v(hiQB`esr8m{p(=v_ANGMNYSn^!%+upp7TZX5sa>3BYYp@ zwTZqq{^Cg;=V4D{-M?QPnB%vP2=B|nYBKf!d;7)N!t#6~O?3K_|#z5u5qa&*s} z`_?~Me^KgIBwCc*fGjrEt=Z|42s70yl-7*Sjt~hc{LFUIsU+Z7 z)wrR45FxCjRIvH{I>Wnyt4g=`)7S<`$H@79Q7;YCj%0c&i`$gz^gC-bTe$5Ca^BB# zTzB!?TpSQLq^m-0n)l*llIf`l^fdii>TnC!^h#E8;3WFycf(llG-|C!a|-C)0c=-m8C4;H|yjN-(>0N zd@m#<>7%hzX;)2u10C``d=K)-6v*n1fOv4^#8zJ>R$K~1aoHaouomTIQcr2$n)L2| z8AH}=c9*gBV$no#yMsQeYd71-$eW2&Ggq=eIoTm>WW&+qE!j&Ixq-1Pm8H=VAC;w@ zjM>%PH-f85eyCc`qf{0CoU7;?ep3T|RQe19v;QU~wk~o2t_AK)=nFvA{Z`|1}4lF!%cZrhihQ2QILF}NTb6kW+Ck0Es(=>y_b21)3 zc6I7EZGPofQ8s8Hrvz$L(U~hjBJ_>{QPmNg&lRhj$qhBsG+HRa$DhBbF9 z%j>AcshT6I)%zo)GovyRk2xZ|B)?0vGN?i6F}0D9yum zzCp9no98B4 zgQfYodkyBQ?B>Bfudut<7@2GJ zMb6!-pk!#jF-sF<&5}ApHN-Vq@|0_mLz|h!{4HMlvEp)R3u~<}6bn}`%BU}=3Bh!n zNTk0c^RAkR>Hmnm5Ky@1vF9ns!BRMnjN)?MRuNkOlwDuPLfUByx)#mRcB3jjZRgYG zEFmH*i_x9?MPn9?I!lB3d&X+g$`P_khy27)A!R=*ib2H6cElqs|{0SYXYI*ALx!;Vk zlRB4J2nN?e1)6_~d&01lG$8<4wsa&)jv^YB@P%t7L8Q;I<7!};e*H3Zfu_L!Zu>}iuFSvo`VK4IE`O8@x4L&^|3sGfMiA-2 z$gzqnU$(<2lxH9+$`duItcAAGo}PSQbqB^UTnh%`V%z$i{q}yqy`z=ZETB0}Oe`zk zb+4+GVqVL6F3~0@imx{>>Eq|)lmpgpeyzmR$IRKfD|c3FPd`%UUTD(r>5eHGwDY0D7i1bYofowVpDy|LT!*;`rRPU`}t z8xiUuM=3>=aaYX8o?P|T!qW9CQl@T}jeC!hvmSO7$>;j~_&m{{1UIn)}?r5kCg8*}`jW^^{pV-9cd6I-!I2ZWLB@~7Ww?6_TF_SVK2+#zJ> zl(n}n+R*Fhw_tjrNT`@r)4B6u%nsf$>uQ?=uKFXhLtDL{SNcz} z9gb`7xP8wEF~U@=6GFjpSJ^nCh(MhQ@&-MtVU+mD|RPF*O2`)Kq zE{;b@ZXxS)YfbaX+K-9pbg8L~qq(j*`OY5erl(>%8V6;@=-uyNLeSn8#2j|hz~u^` zXgu+Ne8IC{w3)pMe)XmuNuc_XHJhlwVtR%O?ZEnt1w>@mr_}{Iub)$SVNE`AQ4f%c#pBT z4}6d64d&JK+W@uChw-6%eYtz+5Z_Zw5y@uw-cJdGeG;3(cl#&E+d~%&#}*bUBEAHTH1ElWOnzhzBcdlTS{T`=%Ak4 zQlB2q%voeSE8-eFHgq)wzpUOUR@JpIazEkV;T|e3j>AIPC@vFVGlI?7jEd)F1O{e! zVF_VaH@M^lLp7w$%+l1Jivsl#!p^EjoyrinJkt4ixPNh}Ky$rf-8|aX^r_>nQ#09v zC&eVKLSyIlXaw$rJsl&Zmn}8ZzhtReFqf=^({qb47# z(1P{}Z&h_~z}sG5mSgKmTQ)4h_E5_-hRl3$+~mnQqCzSOQJE!+{vm%b)tMDDV`!Az%B z9>Y=5(jF4e(Y2EtmwGawQpV=WD5Zd9vDNqbk0zFT#$Km|u@ZeYdra+=(56s6(#(2F1g>$#c&PV7*f#P^* zO8K=lTj#mm<8|s@T5}g;_g>QjS3)`hil{qMvs3r|zV`18Og;2j4KY)C5|K4_!R#n= zSc+EVJ|NI77m5nFBApp9p|Tjw5hT8zO6Wq`DQlN-pb@(2XH8mWA~ZMZuQ^5+{3f%@ z9((XhS5(zxVU0`3wmCJWHT#%skY%O7vkZ-rg@uT$^t!LO=I)yHYw->l8?re8qFX)G z9@KniM=lcNS;xAc$iOLKeVFOWKz|`eqL0HH8x0I0QQ)e#KRSH;NtOnDxMR>TI6`%Q z7-c!EI!S-4^bt?Zl}cO3LYhINGS!|{;+cATwvfxAH682;5BfrV%N{ATkB};d1X-Am zHJBV_zO>~EZ8{J`@Mrfd59V@Rn|Pe4MvV>crp|$oDUeI=A`Rg~atY8VI>Pam-i)pP5|11nKizOIwG%njNAS~TTEF(CC-#T#?YT8~@C!ysXI^k+ z3N+(5dx5h;CahE4C2u9;@pHFuL!;{&<;5E&WhlcNk~xbuLmy=L&Sp*)D19Bwt~A)D z7-uiJi+~Ja&~x|ND^zXXKfCuIu%IOzT3T8|<8{ByO~=&U@ZK8kGIP)7g3K(^xmi+{ zrhT2B(@OP_B3&eWeq5_Gu&JSpTuXqJ-p=f0-*lnOr;clrb;G78Tn%yLj3V7VnW{h* zLriAs%vhy%?@y=@fuu+Ttay?3;)mWyZ&H!a`=8wckGYQwZkcV@J@Ia$B(5`~92yHJ z4^`K2E@R`F8ZYo36 z=HR7LOWFO0LdAnT&yhLvzydN2u0%SZVgre5z9YyZ2;Qe)pgf7&0|lhj)ytCz*b=@qYi^mi;Io!-)#H2kn4qmAQeF0tT(k$5W~u`4B4#p_Y?$L#q7GVq=oy+s;~?2D9L5` zp*{=*$h{r@@e=^)$mE}qfKuWk15iuC`gMqnA~@#5h{S9PWQvrrkW$gDh(WkO&XJK> zE;z_}=Vd0XKTKSd_HNVDH01OLz)`qLqRXYv$*ro@+BRF6mPuoMjaGqyO+#mEvbYbP z^*hwF3)6+t+jUp3RYdBtHK9)TUNF8?mJ@O|Rmo*oMc+uh6=t6Zr>m*}rRNy5*8T&A zQ3e}w-N|SPkrx9VuUFJhq$=tm4n`WpO80=LvA1I;=`_*cCgJC* zklw3C0j^HU`Rq|5^?9w^o8P|MXHHt22wGxnzC-eAtg~=#*hlvC=uB(OOUe{k{oY~D z{HvP-5!G28zY9+OnC-7lPni?$`c2Vm>g@In+HY>1Jh>S;3H=alf#b>Tn0@*s0sHi) zY$T?h09bJjP!_H93jQCI5t?2IU45wo=G!wPGr@hN{&azW=_lg+)OTm zWJr%k`29D{*>7$XBpTU>@Od;{%BwKm``o}2IaW+S&7g~8Q7-Ex=gvLwu-D>|D@o7X zK$_TS_3-Wom^Uni5D2c~2m*F)Q15FzO_KA2KbVLki2vy+o^S&FoHZxMpoh(V!eznS zfu4y8d}7!!^WKH0pVyN1T%%@loA@n8}|wwKt{85KLUf-Dlj?`r=9e0j#7QwiGG*d>1pYV6P*A(>NqmTyG z?Q?yFjyK;Y>xX`CR=Q)Vz5nD>*kRQR$ z8G7-EplS|olZA6u5v8w+LIXdyyon}}THWe4ZH587M!-otlAPZ85~%3R7cOHhox=I9 zL(0N1zD0C*vsm&eUYjuuVAV(-4+LO*GcdRp{SaWd^;KkFcui*P`XOhj;COH_GkKN8 zrzL#?{n-?m(cO0&H|I|d+g{00{^0stj)I6weT#$b&E>22Rm+RMe>^J9ceC@#ij2!O zzf;??PbW@B2|j(Hl0JUhJB9q!r~)dCcY!0mXj{bvwVxUt_XFY>i)*(yKD$kM9slQ? zrJlm=A+}G|?iEE_q_cR?Xv=^!u>fSR=kvuHM%U%^)Fg;F-t%jmDPa>X@pI+(-w}|m z@e}T9?`+L}nkz%6btYu1m;b{v4&zcQ$H|hbBPgyb=CP-x78$dnbs4ulwVM)=o?nRw znB)wLB2T|6nC(yC@YGUvBbMW8Qu5jN0y!Jrj3UgG(_GBmtylG^Mc7@>tcS0bX@=@L z@6G$)oDLT(-GK0Q zKmZC-q%F|0QB+=mj8krE3I={iZMOK!#1$r=H)R6D`nu zGuXV8|5wYI<+O4hCGWDQPc0>^V(IJjXagt*P=X5|OzJ^d1pFR#s& zSbl9ochH`v?%Nc%en0nPU!wruv;N8VMV5PkB#542uCMlqo*9HgdE^BPdP(SHB|ay} z=SRMYO$3#n7vLG4oJiSqFV1y7$`poKh}Z|7Jc2vyWPKO3ian0tiS0=`)RpziDTf-v zDw%DLg&G}RVY)1q>J+Hm-F&cZ!d>QIz8%3S3CI)7%NfFp5a)x zHd4FF0mpLU-`$Y7&!M#y_cL>^BywcEae(YF&oQGNT6PessG|EpRkrqz+j3iTT3D9? zwWCp6L%E&rZ73Oj+ozV5>}J1a6E7H8FTBgmL@Pa?HOat3b)gNR!IX==e$Tb5KmC!% zZg2eGLgr-vR22WC`PH8~`$|mW?L!EQ9xTzv5lakh8i$VwH2f-Jd-ST$K2t`dK!`3S zsEvJuvp2L=uxCu@;KeLU!G4om8OO*q*ZIeT(FG2T1PT!XWutSmZIQ{Yj#ULDqnk_m z2ODHa%5X3`2y=9!IMt3ZrOK}T ze4eApxzEtkYW?h{rMG3@>V2ib2}QdTKB3{l3I*qLLsyUc8GRW|OmdYoW`Fi0uU(H( znW?k=?G5dUb9_Pzz{Jwk0sZ{w3c@q#1mCZ?Az>f;?(d>2*#=x*P#|gH8`MeM=h|CN z%7hG=3^XgP_J2vRvVONRRHK6C!dX3Nu-+hfi+T@DvK#x`ld@2-?|kwp7h_Rr6alBKAWfi$_KIAko9kJQ<$m>)vt zZ41J^P^`l-{tF>Im}3AU;KfsE{d*Q_aVUeplQ`qhslJN}#qb4r(EwJ0~B*){dFJH!)=MPUbX!eW+&Du%|k$XD+4OksS)2WP3ACQe(w^` zqIc{W zTuUwZ@%r*6QZ3I*_ta|X2DXFkCDn3W#h69l0JsD0Y*q{kg6=6V&)xMx(8w?!=;m3a z_^8`>Ry9!NDFecUPPbZH>cmtBEm}@>}P=ryQ0#7#6l5Yqi zZN|W*fHbz|j)L)CHucd~UEjSJ;l5JJ*5W&>6ozy>!5ZT# z0R8uJIIah}ZaH-4e+cJ@^%(*J6e*jU6mV!`_!4AJrS)b3Wd$I4e_JoTnj5=UxYl>9 z<=WW8TLLUD7#Q~v98<`}FIy2kMME9%9|K#%Je=-V$aBO(=~vxX9z=ZGh}`_?im>yH(QsEo3L<2p_dBCD_;OS?iBii6`LZI>ZR}A zEgd@$-Cw#}03&k{IvlaQlNUwYG@fj)Sqr@Rf$l3mF>vkdKKeL+i-Iy-{5>T?BnA^R z#zzSCHeeWoMuygEDl&v)7$&YI?-|{s(ZKUQO-|?H;u2Aw8_0ACs8BK73dp8;O#q7{bw$oLCiNS+?D*-5=u0C4R0aA$k@OWTK39ChD_gZC1`@3h677>W= zj+2nPV=CdbT+r73{S+I9d{8B+R$w9aGVr)X{B;#5s`K{nis^n!>*A}F)FO1f!2D7= z<_|O4eGLMQZ(x~d9;P6YIT%&?3wG`xzDnrmprtTbgNG@#G`%>k&(1AHhtt+K@vq!| zEkOK!wej8SUh&Kpb!+)JMTMYu7MwCSi!5IIo_VFHBy*Dhb%E{#QOFA^`Wvkwd#&)Tgy#{jU6Ms;@h<|>Xhyj=ifZ40H0-e> z(2{b+7%!2l;CjsxWxD?yW(uXUo6{M!F4aYde?wM!?1*T@JOLRZPxh@zwU?kB{ehfF zqukLP<{4avkuv&fx210_0_!`+Z@xBT4huprLBcmz9^Bc4iJ~ySd#>QUyq^49Uiq*e z4m!B_gm5`AV_aTG))}+&IPkgYb#07oHTkGbg*7sq(pVx~xOyv9bf3j}=>DsM2Flws zwm8j{*~d;_AVjlzrx%-b)2&th=os=i+;63@C4_1bTs6<_sOcj6WWD+cxI=;h9x$>I zfnTkSbSq??4sDbM5g`Uf91hD$aoi31JQy)}LB#FxaC>asGz>TzY-{d4`%(vaJfPd6 z5R77ZDTaJVP{I*f`|v;q$b^mWUW19DL!g3Zwg&aNT+jShD{?!0ntB zmC$QV``=!Pvb$D#VP3V?7f;x}*pPCP78cG+knDnhz0uOD`dmsr^m;{7*T^{Uf51N{ zKLzw$fuMJbR*D8SP2=9c5aF!q-DTs>`v87Mzn=+G4(Jy=#{#N@}HyGK11@2(6suT1<(g?qk@vCw0S29V#XNY-9f@3-S) zLp~UZB>*+Zci_Di3004dbY&1a{S%s`fhS75O!R$T%aPL+GvG+_L%T9_{>P zR=bbHh)8$|l5};Y7d|@?iCnh_Zs|@h9|u|dWXfMY6_=hYzPkYY$@Iq=EAVGEX#`xC zT_=C*g(=B(vLX@_#6H7v6Ht}`Vg?6yS;rv8y2K~Orkq8qg#FOtCqjqT z0F*KhppNB~L+ggqN_Ks{^2fC3;SbTs!}dE*onYdJT?4r(?}kn3A5kS@KCH2dDago2 z-yxv^r#Z6;=vF^5X74VD9+qwX%mmhJUUTZ_CyeB2%s;tpS4>(fX@H0As$*AADj)sX z0KMj73Ey$fNZ3@O0HFn9aU3T#)?P-(zL`P3#V9ko#1{ysxCVfrma+W-x7Yl6DLr`+ zkUGXgp8Tbhm$UK#yXd7qc{$;o@*5@DaO6day?|S%4r0-n(wcqiFfsmN zqcADz&oUj0c0_5CUa*r5>NUIl2;4vB+yM|~QhMyP>c0mETRyrG`*<{Qp56+AT#rbQ zBXtIu3ULuMIvZ8QSh!=TzQG{~VjWPvO@y2KGblQE&3di_d2t|W4$Z8<6MM$Ig*7H_Ks{@ZOW@i%s=4%He{|&&T zJeDK}u{GuImBPC^PW`IrcPb`)1H+*~YveY!$EvDnG9Vn>?Xg;4MH6v6C}rw%V*oN1=aTO4mtrKd%P@QG$29ahtnK&w_>G07K~r9^cSbau6LUs zrq2kibS1f*W<={S+-SyxcfGu#iD-q6`Qj2f7pY~nKUMQw4^ z^<0e2nKTO$vsl!7+RA1Eh2FzFF!`tk4XmW#;B<7QA9>G$))@zQ6TqW*LHO~*y;WNe zOZ%(ZR{0VT%{7SU%SZ5vE8~S0zE==jO7ayZej{wMRWZ5G3F@t@FVCL|^JuIzASy?1 zD}&g1iizMtrwAF)t$8eE-;i%N1FABPsxyKvF%f=Z4)~QoLu%JV`>GD+7e!a@S!8Cb z3G$eNFJrZ#!-$+y*bCOnQz4lx*P~w|AM9zqb&Kc1n?4FFge2Od>8a;u18v>EYKO$; z&(JB#dR45Ivz354_T_aL(0CBgGn&QgV4*2)i9TIk-gvx@6#Vwbku5$aMI&&T-sN|{ z_;D(gkSrv0Y5V(59gag!)fzX}9*a4$e zd~s11%iX}f)I)ZKO5VL!Q3B_xbPg^M`)>@H#8|Tqv`J4GZUJ@1D-(sBr*ibSkY^Mi z$-Bj5iibk$U=_Wo21;9hU`1=qH|u`yD>qT`XkE(rUEFj}BJ#Yk~iy3%nnSkU@KA4ihPNo5SIS~ox=ed&KfOcB}9 zzXOcY)ZkyFHN`TrysZTeYGOp3Bw_@>RoR|_sRC!)W2g6po8KVsy?nR!Ox$i})N8a< zN8yI@$N=wkjnqL_A8KV_C--nSx94jQ8(*r+21jsZ;9eccUG}Owl}b^J1hJVp<*cFO z0-RWp7C{~^NYEz~x$ae(JYYA9>>wQm`^R=(zCfGF<#IRetBcd}8l=kY3%8ra$Dv>gW0HiQtC*<7%_%(Nd@Am~vw-XTPp0iWJ-Pp7p66F)ijqRK~w z94%U`fmH#7HKrCe^3vHGn~F>Q-KY)@mm;>|YzH9mt_QurdZTLRDswPYTP}uH0efgf zM{Bwx50eYqz=NP0DN$h`M^5=5tBRjQ3KE+A<~OqWp0y`&LmeIliXQxW168GyYs`nO zae_|1BnsDQtGBXk>nSX=?j78|W1>W3K0EgCGl3o0`npqGm5Sdlg#CD{aAT_vv9#|I zrjhu`7g&j1h2w8wYa@Yv==@s9VNyfxB9d+Q{QJB1PAfzCeY}FJMZKSfnc~CKJ3CnWy?Fi&0HaNbu>K_yo#mpll zWiszUptx@MqIjJLU?fRK*8QI46YL-_eMZt9&C+K?at2Tr(_)1`0g>&X1;>3otnfyG zhZ%ihq5v%o9$pAN)D`>LreC9z2WrJeqebQ zj9vlzrem=}Z#!-Qc2RZks*9i(WC&0b8csk5C0QVp8a)VRlN`tg?`MHi)vwbq_J6x} zJ>g?uot#EIL%W#<)f-=&1~gM0J36j3UL36tl{pRVf6A(_cyn_f`|f~19Cs;rU^Cy@iW4(6QNl#3Kt|)@XIg#(KX-l47@*go+7I zAgAS=%G6ztU1d1!ldpktsd63%@nilvbDic4xYI-K+v5+w)@Hk$-YPJ#uXWmJC;-!# z+1KO(TWvuNLF>3|MTNrkFE6C1i|w(#XFX|G7mLlRu>$f68;emR6Ey zV`IUI=a)Two&mF?1q`4`v!A^7Mvlu#&ODfb_W_y(WrBL;;zg=7`9jA9fuHg9tka^< zYLW6v-sdyjFjUzjAU)cTN$4RAiCTILT(#5S;RG5j^g-02(#}8`D`Y-P|4NG~pc)1O z@;Aqnr zN2x!gVTFNDzwgbLsB$Lr33^CP9#h!3&<|rbX7U@U{Q&i3O4k7_I`xq-7w05FO1$1MZ(FTnzyLCK>JAqMS4AYTg~0Y z2S8BHzRIX+nOz*cZ>d|=h1m3<^PD8++*Z~2@Q{doL$XPJEi*V#gU2*!LQ-b zLSUi;A(J9upJr=M_(Sqi^JEy${ZJ~F<{61g?rs~!%gsACo4<~eJP(4ooB)tU^Q`dS z=+9yexS@@&5$oD>S+jlXXR?1tpTza%wM0mAirxvLrh<}wmfssZtWq|*3rEG3kBA7p zI#LYZKsp;BuAhc-Od#Uyhf0R)43i8QJSUK`%@PE1jjDWB*E#I>(}W;iEoY1J#F!#q zyii@CK|NRNrNlD*vZ`rjzaMe4eCw|++DoN}^uqC%IuqiIJwmvwwBY@okZ{1*b^jCe z6^@~W&d7+j3s4zHSQg3sxNE-9zY<>ud9s6CX=Jp3v~nZ%j1#66fe0l_v`eC`%T>nU zi|l(KYRQ`#1CU6h&aL{X)j*eZ_z=dk5h8x@MacAB0Vdi-2y^zCfIJpalwvf!NE(1M zXbQ7<#(1G|LP5eCQZRare+|ItNHUJCLd?rV`#}JoVON5<9h9dUz_}y=E6b|*Qwe)o zqqW6urIxW7VD_=g9|uaWPY^Hf%G14HJ&j=Aqpw6;amB5C+Ubd`R@!Tz&ON> z-s5ob$1M9rtlK7*FahhfT=i@k6IMCV1@k(DrgQ*FI4R7N=G>2RJ3xdQG>pi0J`A>% zqJC*HTC%zz5?W{l2u%va93Uhy2XZ2J*PQ-{r!Nwmy!_-X7C{Q0vYE-VF|ie}*7SHS#3EC)2g zzc)Y@SP{ikQ|fu^P5NtUNsU{gq$T z3+t=mva*0qkOtCjj5aVnCH%dP#100OWjng{ECR=Bz0CS|d5mH46eGeFwpaaIgYJBx%)P>9zv0v7Y{)U*Z#{rNJL0 z1my2vbV@i|*PB8+5kdB{F+Tsx*l*8DfcoJ=g`-nB|NN9j@dBuyPvKhc(d$YxisQU! zR3Y*n`?LRWKL62Wgfv|VaLebnZLs>#g4W=b0!MhZIOYldz1hFZ_^*Kct*Ov9?0?~$ z6)&tr|KS3_!TtBl{Vy!(zsvZq1^6$|{$Jbn-x12c=M3x1VI}2X=jT7y5VET9q@~OeG}C<*w;62&oAdg=fjS8wVi|_2J@4jE98)_Y_{_6KW$aB|I-gC>GkV; z!qx+hcohJ8M3p}d116!F#DVf*0F*&_C#7@fE1;U6HCs{rC+%gX2L+|*!O3Ne-`KOH>wL=91x?a!9j}VRv*52@5n#I zi-K+fIUZ9y{%Sdl7jJY6LIz4FLOk@Zo3fBuQ9P8|#W+ICX^9zp#V(k)JBmX}1ZW|N z3-UM7zuRE@288>Kj4@WBlenT`n)Za7(3(mC1S`93kM>a5GZah(&tIT?Dg+&ic*&i# zf>d8VlqU3NdCo4=?cj7Py4;9A zD-ZQ#m&`ObObU$@cLMNZ2m}hI?0q;{XlmMW_`~Dit}tK_hEGV*V_h>ZQv9KJg*X@V zu^@p1^#q{o$p<9B!8)1!?(l1(%l6SxMVP?HtMY`|;%xT&4FueC6i1bq`DWo|0nvXF zk;jh)>Ga=1)nVc_sG<UIQi?&p?K*S&SETmR8``4vZMi*sC+4$A)Dp;!we5O^8O9 zUGZn{p3Y;>q#vGpnc8Em_hE8Li zsQx@s^S3!7Y=eqXl6iran{zU-%`aI?jnJY8$TB^^t@V6qf;ooiZ7#Rolc$d?q);!u}mykhmiqy&u=4G#8px*^4g0I7~8T3$~I;2&W| zFbm$cFjN@xYBbN0h%k@&Cg$C?Xu6 zdOB>hIQ^aYeG3nfzOd{QhyIDtZKT`wib1WX|LwwQZlt=`)ux#rw2sYsY$3=j(PCm2 z^fNUTq176dK5=ZRwsG}s9PC0lU7b(K~%g%Cl;zSrHliR2cOG<*Qb^BTR-U+R5~!95;4T4ZI+?xlX_smXo!BG zU~?~a{=431FTFMA`S>UQ-E;EsEbAYT!4a=xc>E(~iEYBuMNqYDgekYB#~wIi#YZgR zEdnA*weZ0x`92@?(vqZq4(3rl>4jZ>(sQsr&)%e9)(7{11F*?lb%3rJTe%1}!WY2U zd|)YuSMu>O@&G4J8ng&&y7?ch3Vkr3EWuP9xXvsbKwW=KSubu$$NqYBaqhZwI5Fyzrub7h|Xsj=+wxiiIR&j6}4o!Iw`jlW+MzZ5O zQ&@HQ@;sR9cdcA5n9I3)L8F%h%toI^sq3X57+%WBgEL%T1Nd)%I!VY66k?URSb_lT zulX4#ON=(hIYA$Q(pq~Xedg9c8%x*OH!7I77Kh`=V)i9j9=(4SEZjhyIArL@VNoy} z&Z3OenlhWU&SR`7Ea+5@$oujbXZ}|f*7!tQ3#SV zKO@9waUxuc??b8^A5fURL{|xdbV%Q|*kevGIU1In1qg+FK>udk?gi{_&&O8S?2MK@ z#y`r@NE(zQyXq}=w1Chw;sAKY9|oZpT96}Uzjsl}e0n6{W4R&sT zm}DfY`$?8(oUioxbN*Qn5hHE`;$1}G#ddH2&Gi~uV|YSE*<6ZkCq-bMHaUQ=EErPx z{%A0oLc}_h@Zw<7t~(@)FtPnKC4bhm4*~hr+dQe$8H`xHRDb}h=9XV$^wO+i0!7dr zmkQN09*Rj=XkC^H=uft}KMClB9-Lgl0NEpv4OW%kLlTDAeu{%~9&>gN7I5&)zne zZ3>a^pdXG)jOsPILxR;EPR!uWP@R`=!tB;r9Il!@`>fK5C;3*x1qHn>P^7&)yflMV zEr7I!&3&(`Q;qrhWt`?2CBRBB3q^CeeK{2^VEmOFn_KUzfMZjouDFN(WM_jg_IT{)dP6GXTGAMGoPBAE0)a`mbNZN(}A> z9XzleE6Z7oaKFMqKr+y_loTlJq9V(~#20fEvjbv*NVQKzE*<@*UQf<3FIcOC@6{;d zhtd6nX-Q!C|51W8#kJG*eh;#X2YiPMO|My4!3;yg`L?K#m9;-0eq3KxxcfaeE?dl| z5_tg|c^#4D#qLG3pOYRQ?Xh<(%dmCLrc77>JvKHj%!5kem`@-MHjrg0Vg%bO;{>>V z7DbF$SGfltaoE3u?#^Ag*EThYyQ8))^pd%7)jr*VghuOCR(#3_%Yqf@aaPnfjVj zVIvpA4}e0m{IT`lbXY}^AO)xCT>6MT=8%(Rs240_Blv}+&{D+F!?9A~e~Nx#p8hzk=#Ms@cTr*A4NnAN4v5)# zSOAmzrNA$Yylhvn*hZRaPuJhFiSMQdN+SN+cT&ug(p<&?C*B9tjxjyO{XZ*S0KQsS zoYrfM!}#Zak?S!ZwJoza7Z!uovRFHb4rGRjKuard+{Wsne|}>Y4kDiTW(=z)|M^2x zApF7Ef|eM&W`AEzED-_a)Xy^hKmOnhfA~9i#k?UVprZh^RxdN-wLhEn_v8J4y$M0w zohxM+Oy@sOMFZYALEK8;%|F5F-?#C)1A!>7Z?imBivIb-3c$CFQqR-sP+)j&>P(;y#O7J{g7Q!!Kc16(uWCe#zAM0fH;7F6q17l4P z_>t~=-vL_gv9|-*BRcctzG<+&$`H3O0i;oP_eWT~ZBh3f#E@ydxKDr;bTL(2E%x8v zGFsaHI7;?x!7I_y6xU#~yQAD&;hmYFSxY47_Nxrjy#b)30FIKO_nW30E*tp}7Y$16 zJ;VAdz8v5!tn9YFMV~5OnJI8GeIP=8x_8CACrJa0XJW&^sC;waTfiSJ%>+SLVaaBi zdes~)7TgPYFbct)oZJ=kf{JP4AV?zwKY6g3DvFA}4($hAmT!em%XBOcLm$Qin91z} z4jd2CLKY|VsN=sIBZ zW)hyC@r7Vv(Byt5_He&M;7PZm7|Z*%nVc3tY5zvq*XpGodjd(DF&i2?-h8jq%T$C5d{-L&V#8y z&cB3TWx&3RAzsRXt_2v0sR2BdXWSAeJaxc)eSUQIWpdv);0S1!Sz1HbDu^}Z>4DAD zd#ZKR+P!>pZGm3S#2ipUhPZ^N*UcCf?a(b9kdEfsR6@KLLE*N&*f;`(Om1-)A#Vzm zS20@L09RN%2?96u1}Y5s@XR+r7vI1FyOf|H7#dS>ynjD*3n(*&|Et{C5F12>>|PfG z@=$IIz%Bj70XFeF!{K}`XkH&x%u><>_cS>eO~%oZt79X4!FD(qdM`fj-;e3*3|t2z z%CChP@FDyQl+o5kf?%+^sIzVg3KNBmv9seZCA>VgXN>T^Xb`qTMei^&qYGwv9%~-J2dXy)c%j;L{Sr&weIjW%ApF>cs%N zIyshjG93$lQ<#U_yLUM$>BbX;@aR*z)KbMFZ>tzDAWDa_PcaAlvv2=_a0v;kpQAhW zNl}I#mqN!|p!9vq!%^FjULam9^3Q6Xk2t^-ZUq_h&qyAlAY9Y`b@uW^C|rU!7q^8` zc3H#ghBH}E3d~2P3N(RDFS=0a*f}#FE8oXt{`+D;@#qD2eox1_pE`isABl5pc@c6! z<_0SHM4dtNa+8qz${(*8v-+-fAJopO3KBRp^myRi=KE^z(#wj6-Kwa9X2X- z*)0pi!4{-QXTZp(x=2`B_hFl=)$YZ@#2pTVhL}moArx8<-Mt1y_6tu=Vig}UEr4f9 zJpat~jspRg+(4F)qJSh$~-%M&Z@*EfdauBsX&mSAQn=I%Z}{X-CCfR z+-Oo^6n@yh*C!xT0IAkqjpRi7b61f;_zjc$b?2q-6kYwMH-Hv?X9rug*$`;xgQUEM zQa`h0VHoi>1;lqut)ywf{ zD&5LKxdp5V71%TzTIbH2A(f}UYZ%~0^Rv+mF@}nnkB7ayr4>iKg|-j~28P19O@9A; zuVM80UtwHEmiY!5#6N4`nTPW z$}&J<4u>jmWi%;g0}4Tmt77u?WMAO~smaowS4-Lj!#iE`^fD53oX9Czy7wDF`1PPN zIMXa@dtjE6SBe|GnG408Th5$eX=h}A1V`}c?IK_$)bKivDcid`NVJ1nHS&ndgEf?w zZdB}bGtwzRX+1K+g-}$SluMEeKo6m@aCOGMoSQk;Fz(GUw=FyxEFBl1&N)i@bqlhl zaF^L_7%>ZkMw6CBcdJSv_@4;6E%_MFJx9S{g#2D+nhg>}1`|l)vjPFk(axTmMc$wL zZk`&yfZwS(%V(il9Qn6h1hH9b!Z}F*x{tIga0j^la8F~)0;12H6^denq+?r--K%C< z(806*n?8_9F}P=svm0&51D4_qTi>6Bp_gT;EXKa5@8 zn$R~=RfkuPanQr+YEZwi9VinTk2Yc3{iKNC9W?_icAu=kRwo=D`$L5@PjF|(pi^LZ zS6?ph?c_no6#&{HAoi%sNr9K(zsA9z{#z1*k=@X9Wae@9H?{%DjQEo@I7*Y)cs&>WjQpV_E+#PKxvb*Zm3Ey14(G%$uzUIfTk=-^?e~v-Z#sc@ zbNbN%fJcLTVWqv4=avx|gUtp_OabCZQM8f|P_7tK*Jx9VrcxP+q0bc;V%V*1TR3 zgl*j3o{$XU@78`}>=?sZLxkY@Qz4bW(Wb@G1VK$5crP*-p3m%!W8OBzEamwDa5Wj5W-CDKk#A*#T{0N zFyoe5E&C4AwvCo6N+t0SHMJBVl-W7gfp5{@wLDbX{Q;7HM8U30cPgM7yAHtpD#BsL z+|+xHPGVZ_HqfUmrf_>@Fn*0g1-eBbuX|>uEWShB>60yY#vc5fJ%F`kP;)Q54a&Ll z2Or@lWhAZI#SZKh-2S)uf{QzZ0&2i^=2b4qhw+Mlst?!Tw`$&i9xEk$CMIqsNBFBL z+BirAB1G#ON2+(`?4n|>(fhn-*$Y|Fx|-~!(?uS z#-B=ychL@ky?1$@^nTkL|8tK88PC`bD9Tz7F z!uYgjeGM}Z9Ww;O;*WSB0JQ(sA?@!#f^M+F1VY+TK4~O@4D>`z-1$xC^G6zk?9{FT ze90exlGmYe5{q6oM*1hX$LGlPQ*i3u`m==EUVyL@MY#~-$sl~AEDMxzoebxZsm0MA zj)M-TlI=KBID0^@T8@uSPQ13rpoKw?MFi9bHbZTfX{ZPWLR?nHXxGLjdT2lPx>D~U zjUm;%KZT4HRN1_@N9dzkPFecOEIn^Rz#~Ai+BNevoVIYmjULTF(KNC!1txMok|Owo z%)iEH{GmO7WpRMqLUb$tw&{gWmCcoWm!I&0erNWqKM>t%cqpiX&^IT1lp@kO<2IY$ zD1Y#u)|b3#vu&Y*l}gcnp9gT0>VLoP7z&_lMvtR_3hMI!jRSD4IQZqNf

    )fst8 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 A=>Px# literal 0 HcmV?d00001 diff --git a/Help/attachments/VarGui/main_buttons.png b/Help/attachments/VarGui/main_buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..698cb47e0ba2923f4c67584e0dd5c31e56881083 GIT binary patch literal 3748 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 O0000#Y<5kp$B?;dV0Di?^QKS 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 KMNUMnLSTZQbd${h literal 0 HcmV?d00001 diff --git a/Help/attachments/VarGui/player_4.png b/Help/attachments/VarGui/player_4.png new file mode 100644 index 0000000000000000000000000000000000000000..eca189e433cfbf5c1093c3d2a7664e4cbfcb416d GIT binary patch literal 3893 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 DWwC(c literal 0 HcmV?d00001 diff --git a/Help/attachments/VarGui/player_5.png b/Help/attachments/VarGui/player_5.png new file mode 100644 index 0000000000000000000000000000000000000000..ceef9c521893a34d3fbaa4bee89d4c523cdd7875 GIT binary patch literal 3845 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 Hu0mjfmc~jx literal 0 HcmV?d00001 diff --git a/Help/attachments/VarGui/player_6.png b/Help/attachments/VarGui/player_6.png new file mode 100644 index 0000000000000000000000000000000000000000..11ce114852243810b4805413e35837c289412d7e GIT binary patch literal 3991 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 literal 0 HcmV?d00001 diff --git a/Help/attachments/VarGui/player_7.png b/Help/attachments/VarGui/player_7.png new file mode 100644 index 0000000000000000000000000000000000000000..d04c5cf6604b90daffb39ce2a6d1f59346c1244f GIT binary patch literal 3878 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 X)j@CB-@ldi00000NkvXXu0mjfNOEZc literal 0 HcmV?d00001 diff --git a/Help/attachments/Working with HS and HSpar/latency_1.png b/Help/attachments/Working with HS and HSpar/latency_1.png new file mode 100644 index 0000000000000000000000000000000000000000..1b207c26fe73373e90e51a6cef9c14f7ba47eb9a GIT binary patch literal 7064 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 Wv|>MW1#r0rNJ3Orq((?T;Qs)p6Xa_E literal 0 HcmV?d00001 diff --git a/Help/attachments/Working with HS and HSpar/latency_3.png b/Help/attachments/Working with HS and HSpar/latency_3.png new file mode 100644 index 0000000000000000000000000000000000000000..ddefebc51932f679033a5bea4987311ebabe1513 GIT binary patch literal 13924 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 H8wCC@O5EFJ literal 0 HcmV?d00001 diff --git a/Help/attachments/Working with HS and HSpar/latency_4.png b/Help/attachments/Working with HS and HSpar/latency_4.png new file mode 100644 index 0000000000000000000000000000000000000000..c9775cdae8ecafd84096277bc22ddd0bbe302043 GIT binary patch literal 9295 zcmb7|Wl$Zw*0wk9x+(7N?(XhVptx+TxDGD+4wnaLHUt}2IyOo$8s0MHcVr8NNnsE)sVW<>bE?WKhkE&zZIV=E=4t{^2v zuI}n&Wor)t0KA}L(?N#XYt2LVnPw4H6tGYvnh9rV3E0#{2CWkK3P?y2t#FC(GU7;Z zDYAk%a9FkyP!g~VSk&hd@Aub!XVH-LHshREk>g+W`#JS@CmY6q1hBrZPb&oga7Mb$ zZ=@sht2T-OH;{NU)U76&P~Bi<{YHCw<~MTQYxL_AVm?@js=f608_mJSY7zef0#s0q zGoW$D1Xlo*-Sz9sXux{zx^v7U!-}B(O3w)r7lx|IJ?FRpd$PdWUTLZQb$Yhi(&ED9 z%{m_-pM&(vBq?BXs>g3+@~wo$j{pTA-*nsG!(lnkKGxQ@5pT&k;6_6AQsIpiS(-p92U1XJ*QzikU-(oL=~!_CL}5t!(4Y zRW2m1g z0Jf^XuITv`o z({_Kqvxkz$4^O(V-0Mf^et6uZ!bDfMcZvsgf9@~#A|HkFD2ECn&hBKJ`{(-820=q~ zv|%*cN%lz|S~yy8;K|bDqW8{wo*jRyFQ<8blb1e(Y3z;3${@%sLRT2$}6^Djg zC2;d~i>r!+4q8L3el#1J~nmTnb-yrzJjqDSXnS?%`@U(*qZp)Aj4y9V^n!DQ9-EKqEt=%o` zR{9>65vm@hQM&Odx^9MH+J1UvDoJK!>E;34emUx88m8j9qCU$UkOynjD97l|$h&%m z_DP3fsdgE0^>(RUamkl(weO$&buG5-lC7#192|&98b3?6>WR2^P`&DeD)bo_67C2m z+i0p(3LdD){ap=l2sx&JlVIM3ZAZzd?F$Gew0&TIBFQZTDPhtZ0@vr8FSGZ zt<;%$`ueAIuz8|-BaqtkX+d(+Zu;Ye<8aSu-*jkA$Hi&nybwyFmPVhaZvl}7qeb-g z*?=6)1C1aZ0bNCLWN}@w*=!tG_bk?`!76QCZS>05G|^w+D^ohNr;rn6S7rXM3*(vZ z+u0bWq=)JBBDky|Rw_0jMiXz&yN3FLpPX%sCCl%b$8Hsbg`Z9Z8}Y8#296(z_z5$! z%CeBM;|-b&(pO4M&>B5G+7FnIeWpn^fUC#r*6V>D;!iw_*<7Jsp$1Nn^$wyV{Hj0` zk*nRlotc98-xirW48YoCEUjR03qiVCQ$4O*$pvvuPP2)#$;~5S9ZqA;1&agCvG3ba zVdE9q)B+LT6K`o#Q$W&*^GnhO&(ie^Nn@VBy8j;!?tu2E(lYh|s49U9jYNlhwk(~T*x2Tnm;2=T3wJ#r8sRgp0n9V|P&x`x&NCj? zDy%SddyyaYOFy)Yg#1PGbn8XIaF|V(UZ_{ObgN}#N^(O}Ov{P>(vH%#tN&FhGQl^B zbdr>Y6d9e#pTy+>ACFr!i%6@?{B=Gi8@tJU)@xIwJ0w(Hlvn$hHy_k(I^m3%3v;jR zr-C*vJlW)s9`=$1M z(vZR$&Nc2G*3I7a&RrK~w`(-Rg)*iLyBQ+lBV08+*vzSyh*I&4S`J=zX>C3RH`XjN z+&q1Iy8Y5%%ZzLOUfr7Ofp=GQ7jf@>Yk+akp61)fH+++Jb2`%& z`(tnG@&1}Bnk-FDSF9@DA@*GPM1@q9WQtt$hqVIaK zgn9UG$Q7$kIS-2S8bsrApOsWH6DH_B9yq$!g=O^ebDvO2F?#u|-UmRdg7 zek1mM%W#ihTjn^;6c~6@Nay?}EP+1(s?*}~ni(1o@|KDX#>_^mT9O7yCdgEcbRtY( zw&(3xso$uNdg1H?n`1qSW}`EVwm;$Q=5+<<>3EuWMj9U)Jlxx>_YUq39EfTN3GoLA zJhO;16*4#KY&znsi*3Jy>h0-3d7BqY3jG4Jdxb=$z6nE-ba}eOjspf@NG4fFpjWp~ zzPEZ{L#ChkUM_V#ch zKg8kekZPoJr+i8Uik4T_{F2la^RCjV*H3@b{29>6QLEp&=WF2D=13=@>#Js(=ltHh zC=g2M6o`@9$@e7Azbw2j(8D3X_5D)8I_~EB_%TDKk>+J@JvBpTf-K|qa-!X#jpWQk z?0)%f2V)}6`|TGQemC51FxCYiksM(zXwejkSdtr4%pI;STrwYF8pQ^7SvrC00c#nN zO`33<#+)!p+La0|5o;JSEF%mrEY*(Mu7JZdiZUNnBDEoovFWxwv{{XPfX$6n2Q0y& zhlst*j9v3S=XniJF$EYm5ImJ>+R4-+a|Q<&1J$*MN14?LDsMs${> z2IP3OS&)pojP2UnS_@?IC&~+5CbamJs+9u42?N93{F6mvsNJI5@m^qkT&)vbU z{}%S>^=xvp^|Wxmzr(+ z4BZVy)1}aIP?r{A7loJRS%z8WT83K#cZ+s8_S5kcKcI;=_`5&w*DDwK-INE?Xz4(> zN(poa4Jwi%4`MEq*;V@+VJr!^>AZv8Azt@eP7|+decKk_#coSOJTVo! ziM>K$FAy6-TxyUK#fcN3EurAV3DnWJQ60$XF+&hV!Z0XNW+L>YlPGBtz6@(y;<=tr z1$IF@5z&NxlTaz}p7EUKdPsV>zr07P0^VREWA9@n0%b5?X*(6#6}DySqzIKG)Y2pZ zg4@G;gUr8klJYlr*&$s4JP!E@lE8mgWk#ss$r#xwlTiG4VDXKb`yFTeobn1a($E5KO)4)+Rcc%@u4U(#kF}n zZfCw08DS^8;ADkNM~(nduovO7j8Laog8^T2g*QAePks&W5Jz{RppacIgE$8V>g{E zQCxmpQXD!lb2eMXc_ss2Y=a&h0rk_%oYs=xlUp<(|IdX6Tn&|F*9c~1)-X^ya);G_37qC8@K7>xRyWq2&MaaB2B)qu#PU(8%*T+F!okhif z6GwRmAA67^-)qjFrKRH4oyW>1r$EdAJ?FVE!oHv0yF_No0{}7gC5?aan)Xi#>Fpr=%l0 ze?Nt|2nx~?+FnqnMo3;bI;|o)BxwL7A=uu|Q2V;jQQ9$aY)o}+Oe^iMb0R})90(Lu zG}Ulh8%(1bRR&VBmKWXcW6*j?ibj9WiatyWgKT~_d)yL z>Ea4%&q0*=i1g6k#N#By71)Nj8a%0WR$03LuDp3KK~9~q@@@aV#}MUmh*&$4eYz?* zigm&WUtj<&yW)lSw2^~iAr>O|)pY(N5zvAqhaZyfC<9Y{iz@L08s4h9p(bqi&yEC; zOZN|=3zS;JmmezrZ0C;g%^X&p;e~W0bJgYrLf5HGW}DSJt7V@CyUEk24o~$RPXtaj zUxO)zNz7rj{3iX)NN=#JB=~p@jTMe| zB4WRD8|7%&vYYSX0jy{icsQnWoQjQ07!O!KH|4HoAw;*2_q>?2PomYo9*09<3)mf8 zr$V<&<*W5eKBZ_gq?XkeAZuHY9R(pcj`b9H@Je2bBdH11{P&8}un@}*k!Je2xiolY zFKmoQ7;x{BFR+t{h1X`n6{1;kxv-=r&N~Dgho6liZqX!)HQ}R>^lAq05`I)$^*x1o z4ZDpC^OX!Nk#c^3R#t_IxN)WUSsqPD@fw!xKr99mPun80-aFWVF6jo7&gvWgI0{z# zpApFQV4;(YBgZNxI(Q~x`{;r${4()aN)!}cH*W1bJ9FezpE{xDZGNWUfYUreG}T2Gj|2ZYyg}gHqb1_f5yIDI)2&Y1l_}sg+*>)|p}&`gEhq)MtG!4D0R_ z9`2=|Kl^q?X)>2u3BVi&xX8Dl6KeCQUm%+qvxs;7pW!6PG1Wn>DM$0Y{eg6}!_|i- z$-BNPjR_exc9L;_;Y`y0yD3%Tz8aFd_t~0uk#WU?_f^q*wZ4iIkL6=1Y;R1KBM1AS zq+S_cx{a^7=9*9UZ^DP9H=oz4|JejKR9t+vLSsQX`3Sz#vVRZ!p6oL(>>ZStlO)K) zQ5z3MZ?WGtQ=1qaAPNRfJkILzeWBy`I>f^3y#nR07grd~IK!wlanuH+he`nZV~$KO zk|~BgXau$7)siqPvv|Q!r6wPs{wYdbSP<69g5;2zkfBddg>=drEB1+N=CWa@u(4}$ zxB|1I)8JhVhM-#MC#4)T8=l$@BLpQ-}C zZ*{)>6L7_cR`e10)uUthujKrX{Qnv)>w!#Uf2}lV-Y1XJ(f((ZDjD%~X2a+qk>}4V zO%7#7ZM?`IDuN7IQH)xp3!kZGY*w0BuJ-rLKt--i%PeRg1WoeTFHO()Y;JeQfV%KEpyORt2Z zr62lmHd&;p(YLk!&o|II53@4WONJ@G@m&~n;D>G6D#u6bepf8k7IwRIUWlan zYT)i3Ln)>2`8w&J3vm=1LSthOaVH6un575sz$DC9Ybj$J(K{ez*cYq{e!GFUk9@kwD z1daGVIBr|W1*MF|$;Bb=BNZCzAEM}&gDZDM0&_iRXiFJ%S)0sU9N~0xroJ{<*C<$u zP6lN6^D3JWMc`R>fi}_ue7QK|@j0OTzG4g|{ODtM?I+SFEOjIoiEi|Dm_9y9Ig~9k zr2+eSGDG9B8TSv7#Y=&MPkJ(`hiYBUhU57?ojH<#7KyHJh=LwR%GfcoLvbV;HKskv zRmwul(hYaM2=yg;{NAfUeY)jokT>U1|t~4Xx=K%7YS(qT2i_%axTO%|x zJzhp4k-0 z{`d>lGjApJ_(i}};Q91hF}kWVm$Pl19ZxW;h*8<6F{O~;BTB;U$;uN1zsWDBnD&ox zAat73LR8^?>qhl0ahg>xV|k~SUKHoNPhS;t*vGTEU}%)!7v=d9a&hiv#yb#M3{MAz z4ino5gDF$n>WnH7SfoaOOYt{~;ikv;Q!)h59L+n$4Eab?(9*)sS6CaWz8G&#b*$Q~ z&WfkYsSL*vnW%WwxYdWoTZcLCkAJnP4Q)1VzL*2RsE~1AGFb-#MV-}~Q14Cs#9)65 zsKYAa4X?4i&&2xGvCMMz$Q5vpI-`lU`oOcTc$Gbe_^^P8RE*Zn49BUn(~BRR^y zLvKtrWA@_BVi4|0&X~VBF@}ODqinA5`OrzY`LVX(XXo}8s~RqM>^94-^;k!Ct+>OF z&;63J7FWx0k(6kKa}u<9Y8?t=LD9ho22lP8b!>(+b5&gn_s_1#>`sK$W@Pp^fa#iY zh3K!LG${7kRaSNJwN>^740&D%@90Jk=5OD+2R*u5b$FMZ4VoO)vW9_2OqchsI4|ie zb(fD`2rBey^=Y*IiX3irQpX{o)-C!idd|>WY{0QVwAuv9wmo;6S}iTZfy$!=W`tbd z8R=_Y*|bV7DmnC_q5;PgTS1&5-k9EUlR=BSU$(jU;o@bWKQZ3DqZD;B`QnR5kG{mg z!e$^W4NpLKm;AjLYxVh*KYB{LKkMLbF-fIVv9}9p(Zq&ODwwtXcrk!vuBx^6&D)% zOss5jRKTDa2jDqw@fzjF0LN4uCk|>k`PVC zW&~lT(U+~Ay+%y7gJ;%BgCHq)gXzXHPP+R8_P5>-g~EY}7&9g=ekiyOF#|b&_!3fT z52umJz>Q`N z^1x4zP~XOG8nShkYGDq<*ejVcN$`G@P~GN@N;GnVF8O9PD2mj=-_#aL-5(oVT_Ny{ zt_Vq)$!i%Gs-~G-m6p7DEy_u%o3yj1LbI@gf{NIgeF~c1*U@)Qrfc`Vs`F;nsJQ%t z&6`+s6GK;1Q{t_LWNZbok{L#(goK4&h&w&0dgkXJ;h{>|N!#xw1q|c&AS&falJXO;YWOu)TPF9V zWtn+s?G|qB92bpzCZ;NLa>l=#Pp6NN*UDGtUBiObN17bK=r?k0>h#e)k~@P$e>w## zMJ9>A_4Vxeb9fCCEv^a`lKI(lGe8Gp)o3QW>`!x2(=l5$STn1LJhn`-MeI*#*euoU z>0Dc}Wg#sxds>{VI5r&bhByf5Dd)*r>cbe3(M3&r&c}awpNaSJ zz#-Bh+S%O*#rTopx2x4lj}71Vqnps_hUSRQTsQaj`+&(Co6o_ci3lzCZt&~A$<(^N zk{|4p<;uU0?{v>srUyT9Yk}mFdY&&!8LqE!X#>rF*rGhi;x|6=gnAS5T8PWiT@z05 z*Zay!6F%6Yz2=eC1q?Z$kHhmOUWB2(-=#(0PUSvXeR=;yjF)-+!P)GUkZ-U{ss6Ul z-dc9)t)`c#VUA+ZBla#qe~FV}xogbS6bB|~a;9HiY=8e2{q7tpH(=dVUFL4sFexkT zK^bovHj{5o(oz6yA!*W;B|*Oy{1gk#RRQ}mrzlEGITQSTnm_qUOJ^Q8gut-ae6~r` zVe!@5z7b|f1}%@e#vf&m;?SdDq{{^b+c&E&lYqJT^r6rnHNMOL4KsP|t&Z%oQoXA|Z*jn=dm4CG~Ic2A4?8NK&Vk15mw|ilP`Df}Sv}+qgtMofEU- z!os39HkTlwM2N-83XGT<<2zIUD2k9D!+z+^N~% zZiI(b;m4R`LZHq*4Xmduv=Hyhf$1nLku^RX-9AYsjTjd@|HQ{L$_3&XQBg7{voUzm z{EUGEltYP$CYkK+P*-Q3iB7|iQ*`u$Jh0Q#G1j>zHWK^M($@fdY_A#x?uVtDC`Y}q z7P2@G>@EDYP$&s%O)8=R(Sa|Co#Z|0>1E%QYFvr3tP5M)LeLv9m3ok$IMV}8y_OkM zC>|#a2x8W`F*TN%>P;`v=t3%Xyz-*g%XZK?;6F9;@na#9rkh^2rTWc6KF(m*IXCU- zGg6g|!&A4D`Ww>A^r~9#UiuPIJn7FB6>p4k;?{m~x1Ls|O7ip3s@ag7{hksu7T={9 zyQtua$kA6bw4HCYAd4Kv4b#igG#_Ri*KYGpv)PDC*6SpN+ndw*|fcW>s#1He~iOgvQ@>D zpHAP`r@JuvBDb1bRN2Nt4&XfDpabwq$sTa=fOuQG!8Gpt>2mRBGY8nfa9WitOWPTU z5meYm&A;UE3<-97dpm^F+L-NR;^Oueba38=8oZk<Ik^FfPPyhl{YtM0RSI&!e^`(>F6LjJ39Xl<^Ix8M zCQD8P6L9WG-f;In8Y23aZrleDRfPRFp!+ukT=g#vqfD^Cdl LRHdsVO+)@4H6y_u literal 0 HcmV?d00001 diff --git a/Help/attachments/Working with HS and HSpar/tab_2b.png b/Help/attachments/Working with HS and HSpar/tab_2b.png new file mode 100644 index 0000000000000000000000000000000000000000..95cac96c1a9559f1b74d1df272915f02213a971f GIT binary patch literal 37921 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 z zo>(&>k4Ldm2#IrEc?V$(zqCuhhL%EE>I@W|XgQ7khC(O1xzXXj51>`Y!g6S-PhWFqI;1m-?i>WjW2xM}_vn zA!Rx-z&jBM`-vQ^$sW4rIw1gK?p{5lR&I(NuP+g`1F|^_Q2W_{MK~nx9>~gOEWjd{ z@!6!WxWsJ5E@r@#S8u#X7UWfI<}u^%J@9mQR(UYfoox-NfmE(%Y=#2W1>YvZR4A}N6&lXy+iwFwuZTU|o@v+>J<0AZ7Kl=fGS}|54)wJ{cY4XoZAj)Z z$rudQQZ1))dqx)va3w-zh;F({K?xnVbCX_4LQ9j)zMEe3YVj3yRzr-@!><*HR6hv0 zEGKmYzGp+|{#+6Pv1Qs27t_ZB9H#~oD&REkvdUn{py9g!Lxe2mT1BYW1G>pXjsUl! z!MQA6hXy#z$J2u!l1KzL6Z*jo^v=SrLkwZ5$oVoKr$E$-Y{Fe-#Rut+PEzP`4a7GEDfTOl4~x9mS3HH(0a#AO}gIq!h10F-KZiO0=8 zd2u5c?zHun0L=G^0`Jc$>NoE3*D8RNOJbwJ4}tGKIEf%1guS(7P?r2|_Ra7lGq~1& zhS|D2*th^pM@>$e$MbgPEFlDmC`}TaGRR99xkM!k#<$KO}m+@w><%~gEEFq&Qr*$|DsJL{$SDxqdaz<{el3 zu2#aGMJx>r+SWT9g(nyt3$NDmwZYtrn;5b9F9#%i$ zs*SthTd)L{bpea!jE3@c)2~zR2aCj&#O1y6A$e$6cPgWyQ&$HxzSmfi>aBco6Ss-G z&~MXVel5|C7Wi4YqoH+mz991g^1&|ouW9G+Txd=@HLc$fnZ;-Td9759foD%HHOIps zKI+R1no^N$W(&6Nf#Ze5QSXWlx@w*KHOXsK1xK6=Z;Msq!G$IiT;BDj<9vjT>RE!# zXZ>}b?SZ&7!t70*fB~ttjhiZo5Q;dJ+lHcFvAV3$8mUD)rnDVy&$$g*!hjfTwH z{snzEEi(fA<;X8i3B4^;s?!Sz+n(1ZmlIrTn+%P>zk&inO1 zJg8F91w149f=^4(RgxW=RW~tyz$V0Jtqg2CkJR4YiTNDZB#*sMs3UBZ;vBzj-EKN* z6@JYV)8$_De80zCvF4abOv#ZKr_VY3jxY+qR1<2p-yBz1|%8R0G0 z5dYa%PL>88SpJ29&58izYF&h2JNxzD7@6lCBgZuEnEi_!Psjq8c}W&;wd9@f0*@;1 z2^D!TN9Z^_`973@ddnmM7;Wa)7L}!cU$})uU&IfTqmP95uk!<=coV(x_p24TTIvK@ z@dnSz{+w`a5^0m6QH;~vQOdW%EV?1pdnxr-&rb3;hrwmzTG;YW z{(wlEq_6vHP+mHrLRG#Y|3RL9&?Sbyw_yfgZR_vMqrMxFtD&FJvy7sHiOTIPZw;_^ zDi>b5ZW|xUvEV9erX)}OVF-)e2$OUE)nWc8{+wLt6qOCZPxLdejR3?NIjI`{V)Od2 z=Za_B^2hVM69zAc+96QIhPso?b7}UjR#g3e0pD$5GZ4E$iCZWq@OBta@F^umRZQZaYD)NeGdnrxoD4r^R{E zQ|F-j|KM27%FaL-+N(YNN}bka>-v>lRSjc|`tz<&&A^Ryx6WMw0NP-)(sb|wP+;07 zTgsb=4hhQ4eAH+RRrO8;0!|hhGgYp4D9b5vG?^FDd^tqB0)W4Yi+#@&9S`%wzJsFd zit)y{o2>i-u@jXm_O*He#N0BCKP4Gq6lL;V3Lpm*@SlA`N_Q_y_3>S;+7W21av z1W;Soc^yyd#76|S<#j~P{m-qt-lqW5)zb6-@D0G^%Xe$Om3IJUqXh`%QzJk{)YdLc zv)n1d*9hg{yE!eLHK=zfehFG+m}Yy=jRUL&A&UsG;yxXI;679N60e7)mA53hH%zcB zunA6aN#jn_GJEg*(|5&rUW89S+-JGLUME#EaT!3S$3cyUwIDe@0N>xg-rllt3N@!TmbujaTuoGGu~V`_Pb&p0R;j+f4&tY(LTm`osvsg+ zh;%`B6h-_lUJUHL}c&yv^9HFb4NzYleYX&q22rlkW#THyt6rgYoQeo$%bFg zvm>rFyWaiu^}Snh)tTYaQI;TnFd>>=+&r!xzh!C+o7(eE3JWTNcN}31A>#FFcv}xd zdggsP-U0}SC4%eWucF6y%q*A1t+B?pdUVSVs0l3&gsZane8=%fbqySH#ub2|EJxgH z;G6(3eLIYydMXnC^)0W=ORuR#8XkIs&EtBXBJC8o;py8w5DZukqs%(bZJxdYU}syW z9(gGmfthjg2|!7e5YSAUz5|7n;WuA_oooRa)eDbNJuhHZii{hvmO<8*owt_d^I-F5 zdtHVh5-RX>{i232f1w?-S_QE3xDnzb0Kc7?oEMB!4xBZ))_{rB25jZH!F(DEkG`*0 z*&dm_PSdLiW!GO9%}9NB(@aI(!@~P*YiCs_o!P0Ubhp?$o;~hP%LfN7rYmdbG>H$w z@uwF9Bd|)`dBD!1vyBw3{0^aTv=5YAHYQdn#_?x`otf;d$HaD zFfZi4Qr$F|W35r4?ltZA;?`jPZ0R2fVxdk)VP9nheibB#2aq5N8>NVTf2YiO{h_5>n`}K}{(`(fVWBM?$9U)12-&5p zhG0DM5DOgVJhQA2|3#F-RW_d$;bZ#DSXGm?UTAF}t|dz-T04I^3e^eEpyU}q-kpVl z;T39OOHefEximI{$np&1UU5Z|(IQEy`zzaDOM-*`+ROwX6AXVBxT5eCer8&*pLv>9 z(~UYDZ4QUkrVuT;MH!3_Pnp+t)uyD~&_u7bxdOo-m714~IpHWjULWL*Ko>f_*F*@w zb=vrul%k!=m!+!h`e+`2tq5uInmi@R3;>%|BTU2WY4&3EBHzjb9U9^iV?ui}LNSv# z^7b$knwwv4mxR!{=7=Ho?Iz80$BUvwnx=9RB~C{2qkXWbRx5uCQJrLeANG&~d@^I* zB7BG0LtIK(q|n^tA93F(lHtLCPha-MA^RwEt?Gfc`iazT@S*u!j@6BC-|IlTBCUUr z;BIzdcR|?axsm$=X>=g}T>zX(O3Ss8xV>UBL5ZKd`71bk55f!Pz=f3Z z=>}qgkt1N+o%0bQ5|M;7Zl%;XAm-_82=y625)x3|El|#HPcH22h|(uUQ&vr{CBc5y zc3mlG?>M$+pt;4J+=e!!Rjrk_aC3zlA0py*3+XK6Nzhm4E7u*!w#nKgRXn9k4x+7S z$URzatkwd~oLSV%P||2S;Ka1g${+ejD@q>i539hqr_R=Oolc@7Tc&`5b`?)j_+DJC zEi(YydAvJ2>rp3_6m@dpoW=~q!$5IdHcF7m-IJh%*ED!8aM#nI_Asvp&MV3fwVuua z9YAI8`1dP5heLivjyfyx*ytmsHvDzQK1veYXQo13V#J_ON>R^6wgbp(mEvD_Wb{0# zpV36iw$qGA!eu-v!>`ro)sJJU00Q_H&HFQgr{s_t4TEBud5qn#=NM(-N(6jODX&Bz zgAUqA6Ol1-Mh>epKn@4k`*eG2A7q^VlLe?R2`anlLFneR$e|0eU1X;ASO#(;0j zjg)-fp50J^_RCYk9Ipxcvsv$2e${nYXymI#RdxD(v~*Z4Weg{jLl#xWZf+!x?rIwI{&(*%S8B$iK;*AQQ7M`y_hWHh8-wds6wKQ|KFn08UxUW*0sjvI{&`l9Kx?JRMJ!$hB5FjDGQ`37$MyG zxagh-o8q7==9LF{6~JuBLmHU@UJ%euZGnD zdbBGt(uMb~PTxi92SCGWA+txA{71uXivSw-e>dX)1Eg&qrS{tmbM!x*GUI|(&Nv9q zo)ATBvxjDQHKPsJ3_&Eo-(4(df8U03A7Zg(t9ngMd#7umj?lm_x=Y3;kE)$&X_GeO zxytB^ZUgx@&YYx(A2&jXmVsk^tD^1E;tmjI$-EUqH$a_zH(AHypd{Zq3}CAN>S~f` zjsdN9>gkeg`w6C|+0P!PXuz;LpDfPOH|^)10%dwB_=G!?#gM`G+WL~?IL``>X~qVo zh7n3Vp!%9Gw)(kLH{OfHPe249uk3cs*Vpx^y#DZpJmp)iG`^@0P~aBP-=qYVRrb+b zd3w6@oQAVVOt!*)qLQpV`{F84ZeI4f8r?(Wd$zj+)WLrBd-3w5^={S1{{yBS&{me` z?SknIuP=`#Q!g$I=-LqE>zJ^0go`hw|o!ijpZ-R$D6yrM{e4m09_-xF*QZX&+&2#9CHpp zw_0vxrhskn_b0q%quIdgBI&eERc&XLJ3yB>{1WzUJE>dhGMV{)IuuCY~n04<&dLc+@fI z@uGAa&UYnwznA4XhD5}>JPzuH*HP_8=pxfL+7bHEmEQt7-=`c=N^pO#Sp$XEEhL_6 z`8NRVJpi(P&h}3)=A$%rVep=yjw1aqFdnDIU>8i(=YVdFNl954{(NM-Q(^zz{s|b2 z!FPGu29O0E?8+4If#HY~=)3BDjbd9pPc#LL{OhC`(T#SK)8wTE*;6SeAi9o%uyoFuIA)$jdJcm&+~P{^ zfl$cwr|!#KiwV<=%DP31McwZkkG~3k3=KmKzX3005zD6KLKLXQ-aQ$oXn&PF1ClS- zfzSxyhb|r9FmC!S9^S`)`X9j|q3h{c{XW3H&|d+Xe3iR;!4wu{I$3sAQ^)>vT%G3{3GWtTEO<=a4Wtf!ZVdtj z#Pz!cQ=)gZZ;2zzbEC|Vpu^{WX(ZQ72T<}+8ZFB(D`0;um;#N{NO0bbgeD~^;7+#! znU-91cYmP7x4h4JLPkrJdJ4SkQ{x@%mv^Bk(dh(O5*G$qnN}YF6+9b6&=>Bt#Ckto zPhJ5!ZPoU7C$vY~q$u74^EkH>5QzbDGS8}7)&=wa2Z%UK`JG@L>*6>#V0ulU2mY$2 zi>K4($~T}^_6!t7PjIjy6ilF1GzRY*cYjFXaE|jnY@^B0ey=uke)kXdCRc#$eQ;fM z7yHyD3`gPlE_+!=!r|0E$JtQ{wE?HD_gb5Gw>1N;7K01;yY>Z^p*;gCDN>$syx2o3 zwn;(CtZg2|z#t%3&KLmQy^ksF2KbG+qxaGEdkDIdQcd?Mubm5@D(R8X)B;T!$A9@s z%=z;GkioKwor!g@J!Ecxy`8nIs=AVP&~HLUEBqf8L0P(pHqCTu(Xx_&M;D0bWP|S zm*-hb`dx!vzoEnd7O85AwrDMWEQH9X_=Pt=Y?1uS7uk{!X)7T+m4eSEZ#VP0D*y;w z1`7YkJf*vEG&pG>b`XE&_fTC5xW~3OAUh&UQLb>?V#>rg+j1+7%%r8Z$FvB>IMu z#FUaY655;&P>r&}os&FHJs@pp5NxZ ze-}c|Z6}vCU!(ViNjMZ};s5ldA*T@h3JoK23E1_z^Gb;H&kg&dRZQLm zuZ7Qymg?aoS8wwNQ9xT40ood1zFfUEQ@V1>ty36d9iTE$&Zzj8G-g)P&YEHndZ?T& z$RfPbYkHH#nJAD-b>xDG`Jym%_EbTPpdeEBx)j$7*o<7U&40&l^h;}8k0ZpRddH77 z@ICI6wvI>ob|bLO;IOl)BmB|a_&~(tQ8QMhalyol)c2W0aIP~#;H)s+MllZ=C4wVT z12pjKJ5-Lq&y!pY*wEMMFxdG~px(`CkE$YKNIJ5+}N+O>vtBoR*KbL#xG9ACM2 zRg|^{m&nZ-L_jK?8j3x6=n|IPqo0Yd)OS>6M9}2;2x89oh(UZp>pdn*bgd8Nse_e8qAu`G8U1V zJ{W>mxhcVB5Bp%MIfZa)x)UgyvRBX!1P48wny{%ppi)$dN^ao3&|HAJK7Mbr0TNNy zS0l_ZhZ>VfKTCrGWK*tytc~X-X53F)oez1qPED6np88ckg5iTp0!gCFN>utI?UO=3 zx2i`wEDh%iOk+ma${-msJE@7*3Vbg2?R8GWrkSKPv%O9YA#h2p`va0-E$L$aGO-!K zaGLFLNZs1w;^#vut%`8kL!xtL$RB#Dmj78txS+%nK3Exh7bWXy--mI%>kF8q6hrBn zMNj+NZ>*fRpY7TPVdO2vY%}~3{mW7%V)!s!gJc40c*g`ZGUnDOmz_R=t~9bt;1jNK z9{zZJp|R3b%1F}bgCEx-W?i^7(|OncBw8b*pQW4|&b*Q@-Nl1)N0kRRFGCQaT>Oir zI?J#lU{V^CA@NCy2RlFDC+3D;6Hr@Z8YL^0O*8jQ<%1@&k56jEQmD}^>pNR=zd@m@ z_tlT0n~Eytzf4ni%5v&*j59KOi%qJ~1Px1)ejIAe=M@BdR82jeY!{~AN|yuE|-LJUmZLm4)iB1`Z?M^rDezy1tC%D%3pb#WS zqac%JqX=Ggit$Tc)nnERGu4Lm>URxo1b^)#R%AjF7G|ASU+@kn8wsO8vPdl-Uwv`9 z{{g)SH*pSAJ?1Kncy6sK(~7mqhS?k!XmW^Uq*_vu`N)|1TRH`Nl~IoMv~$f+QV5u8 z_5L+uI9gb!<{!grr9_%coj8Zza3d7yR+|CDN^vaVJ)NSE-p8ad+?&6>K|?Wq`l&?K z7Jc_H_#C#->Ux-=$!vJ6;l(1njh{?V7NH<&5Bsel%4pQO0Pzfl7d+Yzvi&Fms!Y3a zSRGP#`){nb{5||K`SI@#XMaFneF^e3l1J7GXRAz%{U z;dbiG-X__~du;L7cz0m+IPVexkgwRNs)&{j2g1W~o(9U{j>YJy8E%_l8&wNpQ(6v# zlTG6_!mnYDJv!1o$qxs70)$S-2sVP7>A2+$4o!+i`+Oh!x>TZa(lAVGCpzgI= zfM`s=9=q=P#6T4-;f!p$bNbE`#E86|rnXcaV?6LZ_J39=TGu}8rgKr~OS{krNdF~t zTlc3(zy*+iVSuU8yS?IXgjG&FsFKtI@_4vA2-BTdrod_=@G{c*OC48k4-=zzBsDN~v!`aRPkXY1VsyIHcH8@O1n= z^1a^SKje4Te8vl7X#4?xA7J*bKEZ z*G2CNp!;?J370@6t;s_OD6!0jXMkh4%*07_zN?FiF}^piemVSQdAnjUC><-DDp5GR=a&0~4D5h_ z_n}d|$Arzjt8u~Wc{ftCk}QYF%PuNALiUu;EKr1W1=zRwn}*v)5XPRocs?tjcq<-F z3gx_jvDr{)<~{||_@{t`i#qfH4%&u5L{9O_w29l}1*NAi38!c6Z#rjz3;!}dE${a6 ze{p+#*+z+ySX?pe1T1@tz&*?I+T@g^s1%i)l+Kaih>3OgMG;lr%c=)pLX3av{>Q{% z^`VlJN)Hdq62AhT?e@~Z1LwXKMB@Dl96=uXiLbTuI#*rWK<@Yz@M&|V5p-3dx)#3* zTHuRybo3bD`)#X7zv|$}Jps=#HvVwAG#cpBU?O`XyQ@`PLjO*+g za8|#v?fY;+k1rlvjT=fwSJWaUeDe4wVRe`8>(#ZLaR@6`(T5 zhb2YFab|FyfeFskYGU_YU%((^ON6Y9p=LFfPveB{5?cCsfBL=5vuX%I zfr`U`O44dmDV-Ab2+usSevrQ2-OOvhDeT?v<_hTz%qE|I`=;qZCTT2#fE7Zjaz4D^ zS<4sTcy}oKr+7ftlN35pnC;`?{e>ZxYvVf_$)u%0K9kMRaFNHip4!VU4h?OKCMGj; zE1ZFhvd!yns@}4xZCMHJBhf3%j^pJ`^NLb>Jqod9eHkE9N`|^{N0bAS!g!3(a13MT zqK$hk!zk8VN8wdD?h9cj0@>e9-lvUw%F6_&L57XV^EaUP*~(V?6PLy0O#n?R{F zS3%1UEtPmT7y>h+9q_6)1F^&?n4wjZ8m6@jH>eW+;XOz|06N}WSYt=3R4Gq*8+z0J zR-m^oXG&Q2Bl?-t24O#omtZP;@^VB`*rWfe#G3G|9}1QQuEs_1{>iO)vq2(NJp9W~ zRKXFX)nY$4hKHZG>)yTU3i*&FRs1cH#X1y5CzyOR018#RQp-GG@&mDljH}%ziuJ^g z3T^=Z_n_QrDGmi4i3qbo?_mtvT|g!n62XhzN+2yQEQb&fgivN&a17L1aJ}`Z`S{ZG zo8QZ5gF^-WV~I5o`ZA-!If;6IX9##GdcaU%w`kLFf`(^Ecc?STzIT`#50${!Z%K!9 zGW|*gb~(YS$vCHp3urptw`WJ7%wUYXOlz%M@pOH#HBrk%-2_bSyqZnQe@24ahu!q| z$;3|~g9V|~+{CvCYD3^qtU(0}o zhfTZ_(D{Fe`^%sz+y4I-mk>d^yOEAXBi#*(;-Zl*k?xf4knRrY4w3GZl28dLNu{L( z_i=h%_x=6;X8!Y^J$pacGd^-)E!MftI6m)q9r127Bxo1Rui#hp4p`P9^cAFx9!lfv z!DVM}d&C-FkcoSq6xq)V`XGiS-D^+0w#ec8Dy`kA*&QBFy^RwZqbP0Eh;ztNp?f_K zte1Ra9fa8@>6J5{Ge@IviGUz1zH$FqEAUd+?3j= z(VBTJs#GEUpyCd0B5DVw*DKsI>)Y#JKgda+70)4MbGAlUsbhw{L-*2trx_N0=MA0@ zpBh=Hg;k?<@)~~?8`cf0NiCJ<8w(zn?mvm{Aqan=~$xcl8t-$u#eT?_88N^rD zw$|Rkt*^Jz=85wCc&2~x)S;z%6>)5i-S?H)wUnafd`a|Fy1~<;d%D@_q#G5*k~^z93B%xZ@ENkD2kO*V9mg5Hi0A) z^DI!xBt299Q)*928xyXh+``u#+zTW5;(jqk)PT>);;G3^WHC>>o++07%`+S&h;pZ!J8&;310WsD&xK{rXcO7e-H)NLSH)l8u ztMpY74Doyxao3|3krsusMi8FDhK;zun!9xWRS)W)t4V)NAIeVp*XkNmZ;xN|lB+aY z^pZqP2wb`eW9$4G4T8J&l{DRd&Bo??3nwE?&}P`Rp!gGV7$Bov{rOE{LSpXxj`_RN1F7gc zUUeTY26_2oJ;KK|@HRr0tVbrOpB^K=j@+GpJYQAfVS6&kh&;!myLO{jga?%y{bbOd ztI>VtoORv%q{MVj74b6JFKld(S!mYid4#gYt5cp}O++S|WlxP6%_FXkD+x18&j5TCyO=Bs}tfZ`=`>0=?Lj$}Dxe z!@#B|{}K7(TJ(@Vvl4mV!J)#POU9P04hZGu@I-?dkC%%h5e6BHo)`rkj)WufcxPe2 zSCu|IW%8C_^4f?*T#NuN(k4(Kca|95Z^k}nkk%DH*?nW@*E6{7gEKiuY}-Crg2Kbx z67HVwam)PRBi^EiOtb$d>@)KR>=IsQR+C{jNpEAWu26UTR%R*#jor**yz#p};qbNwgknh`a*9*sFuq{BE4X3Qhn{Y>Gx(<{ zQ{L#lfG2a6f3jUHZFG5c2gY#>k2z;?Ez1M)(l^-ZM3>dcYAVuy-i}1tX$LW}II_LV zR6e3~d%n`Tp6Q$PU2jvkiX*aU&TxYSXc$*?X~gR}ay+bv3cBL;1NlEc;T!sVF3=z) zLBd8V8eif6pzB2(xe(_B8xC;_w_h4=qFGyftLU?5;iVj~JNl4QImMtckWFmHl8F;F zG+3`o61Mh@GF(dV=W#ftmxBiCh|Li1w-me&)WzIVz4f2(Z5bib+$?#Ka3j6HOnAZg zB@szelvNg-{#yM=#({RVg$O+B`(N6EE3F2bLqDZh$RE?PF6 zfq|9sj2tXio~}vQBv(&>n^?p~`u zq<-XkkZsh*e32k}73^?KPo*As_crG8bIW5K?;aC#%8Mkt99m9`NfXpKxd5{dBIiZD z{N8sceYC&qEx7h1d8W#P0vss!23!}<+CfouukQX^Tb4B#BDX7<2C}*y0OE3 zdSi9#X|m-*VE)hN-c}sr1R18d#o(i8No6e+Dqy=JccYL9ZE-&8|5aRYG6R#V*`NwI z;_1(sE|%3>mwU*6Pxhvs*d@9KW2%=Uydwk@pdPUg1>_+m47Qvb;URAwHZ z1y?85Vtj;AVB{)CI1SXL5O&&`(b73!Ms{YL^pdR0lH&`&Oum%9TBuh4)f@XD>Z37D zy_|)M!APRhmw;vh|Bu3?wDydyj^8P+wV1V@W%P{Us0($={UX*9^9xUOG1KBcThWoF zPKOyw6Ua6*y(k$&j)_3P5Ww*b@>ZqVxi~v6x_A`aQV887Wb$5+J&O?6(9+gkh_qA2 zbV|T*Tz{(h^}|!q8mGwy(c+{`6cl-nBjb4DwMe^=aN=TyUix?;IR_6(letV;66-n} z6*>}ndBLI}E#l7(hJ92(BeFpq5b!OQK)Dp^xtC^ED;-4gNzVUW?yUnR?~odKr}==j zOk)$hDkY<;Hxn*fb1NS$i)!&9x0JOtmkeyA@fX&4aU2fTBpfF?W3nj?6-HaYk*?U| zBR5o?kmt0T8Xrap!r^(M$hup~#GwJ^FkV-9NVwru7P6xy*_sn}9f&H^zYvWgiFrYt zlI3VZLr7W1^N793ahHk8a4C|l`dyC$b*K>5^vmZ&g~u+5ALWMjWLGPqNo? z!rL@vqt{gM+RcDsj+B)~?q?WjBI8+e#IEd*NKojmY^q#TPSF=&BG;iiIZe?p*yx+c zHzQFVv=61mgl7c$!m!=L3wF^VllM%@QS~iJ?wxuU8eV$8q*G#Z;7H^H`l0QojrQ@? z->zfb3OVABrUYf(e~$XToH=Q{fzIt{$%n71 zC{D6XFs(Y69Zv8ILbf`m)7LnU*8)3&bZ~peRY(n_kK|h}59q@YHrjgS5w=h&Oi=Xe ziqyR-FN}P`*;TaqHlN2Xit?{5BBe204xLBT4NbFPM7K>_80E++iud=$tG`RgDP1-# zelTl~wMLQc6o77>Ul^*)^vLss2GiveOzP~@85$$o#3OjU&m{UO$7=<~)U)i%ThT)m z=P`Ihvy~mGuD1_Z%W!BTpTfsnUSZqsPriL2&c;%A;<`>Q*d#54qA(twcr-6rx!%7g zprMfc;*O3>74G$`QV4OLXrK-qw1(fv{)m->*(VDxf06pq>|_$MLeN({SjmdZYcj5R z*gqN*!=4b`yVr357YA~(l|SmDa?5Sg`?*VdC_94LzDHy9dfG=Hv+uiUnqUZB+E-;k zu2G_u|D-FJ!vSI@kKUy>m7YL4=(pjwittvqJW+0HBIZ(6Y{*|I($R~797vov& z<^ShZtX`pR-p+R&#cF!;vLd?teobcecXYdcwQIj?B-LI0~FS)lW6H{_bMUwW{_(bI{_TB# zkQZG_P~rS+HgMRs&v^mjn1ZC$cnC+=E=!I>#f)-YUO-nT7p;MNYq2e(gtVZ`%wQ~K#mBEIxxB;QDzjFTSe}16 zUk0fdLo)XB39LVoZ*rG?0iTA$cUIGc#jz_-<31n6T_p`$nIZwG>r^U2pB-Ak}MDSQPK&LyzkD2z^ZV5_VR`~c)U{e@}+a#?x`jD!tC z?;pjJKRa*iT7Z4XTDS^qg(a<*zQzBrJ3xH34M_RZ+$?!^AdH!<2Q0QF$jQ&~zw^X& z2g775=ywSYTmC11?Q#g#{0Gyf+z!ZozX77Ei}c06 zLh%4}<~$@#AiBox0&xPaKu3_>aRbrd3YoxTkb`J5?C{zxvPpgccLXewTA5xv=Bkdq z(;|AdpP;12zN_I9r)1S)w|wR+iFXcyaXY-9INKB3sVl0QGd`?GvK0t1WxFI)U+&gG z()`bb6NZYKPN4F|65b)Av*#tyG8o|;4nyMd_iT4VD4iszQVt($gR^n<)#?rtskE4= zx_4fEf9_~AQ~nTz2N)|NB;5d0^1~1a?k2??5d)*wkkac1;xSJMObTNJoM1Pg@zx6B zMk=Rf(zPJ^FAGJPR=jJzg5=_Q3*ID?T1F8PE0;G=EcwSlz=kTBHfbAVKO@(9hcQ87 z2hdlB3_vCq3->n)x$QS?je#;ygc@}rZG3=9R^)XE{IwZM$9`N~d=PMO=6{Hfj3O<& zT;w~>J=6-EbIIA#k5WFENO7ql!!V04bU52v;m>6*oBhlXiLRN2=;xO~Y}xhMDabFi zfy;N~2MBD97LiQNzx4MtZwHK)j7}s~lbuW`kW5&PhR@g*(CB(W zcRHiO^_cOVqUk$q{5X&VEB&rf^}yPf5M@lHKN!V&9>iEnSt&-3bN~ESSXE1N`g3=? z473Tos`aKw7Z9j?#ppThoTy35AB&-EXt=j?1%e$1A&;*{5}EeJJayW`bvt$@3Sibu z)>l3tKbB+3Gvz^wQJ7oF-~%x@HpPD*$#9Jijg3x5VJ-dzO2C<>PcM}~kmVMH840?I zx9cOP+lRS+L*y8cCy(2A#^t{Lm@T4Uj=Gf&K2t|!Lc!S}kos@V_qWZR*5$^l%u~@6 z&qTApEr`+(-t2V+N)y+>l+v68ew7v%8#Wg{QU}p-bLxm{_;>S1KSDhB&LJPi{G2>Q zbLhW0Cwzk+Jz5VHl+A=B|{>sS$<0%vb1FVy5g-9YAm78aQ1O=+3|D*B6A&p6lFK zaK+q}M}vQ3sN$HpX7zYhB55MHCik$|SC>&53Z+L3QtZuAK~e`>sd3JWgkEnh6$^7* zVXl6O@oHMxPPGV!F=cJU{02f4lKTqn#KduR_2vV^Pe>dZO^ln!m}G59CiMZAhfcd*yukVf5Et*Qh3b zsOYz?XZN@*v(~LmvX~N|FKBuXZG@ddjGHO|_pqtK`I$`h){RCOiveF+K@4`Z(Gfpl zfhsGKByekA!)x9`XnTlVeHnMW-sym?f04dG?Pf`o>cQyVD21 zexlG<+o}7(WPPjAW~5SkpnWZoG8O}Ij?pDM+zTmRLXIMe6CH(!N$2ysPE6BMhQNpk zP>r}|GjCN|+qi&5N;k%8bKwZ-G&9*AW*X-qBR4(d-aiDXJfU9lrK=1Cl)jtDVTyCSa>`DMZq)jJ z)7?IwI2*7kWp!9WlWF9ccE-!q0LnUcZ+snT6g)vnLJfObS(Ea!0@#8lyv^>9vLbyS zQKgXf4|8R&m|*vUY)p*MXFeNIc53}ZIvS&XgWJzZz8!5WF-ss~{H%ORd)C&7Ef4=a zm0s{_Qbz6zIb+1FG|_8dBC*b)w)tL*B#k| zd~FEVNz8e4J_r1wN#kK6aq=Q8Rf{rw*Swbv4@)T1RA(7~q+|45TiTCn0i&m(o1+~s15e^k#SfXcBGIK@=0!D#xv~wVksKIw5 zfIA7R%(Y-Y=ode%BrXZFN=+@&{FH+7VD04l^9-U~?7Wu1W1h4|0u5|91_q)}TaP51 zlQtt%iig>xX=IP|t*bK{V~?exc5|~rx$GZl+X&8-UqvxNWC-$FN#%1ZioT1x7~l22 z{J~)x$7KOQ8<+Nk}dIN!BbItL0ehd-)nQWn%h zjXi~4@Mwbei>IbRX=d_!u~($XQ>*zKy(di_JWDB3D^3$pZ_el1!}+o7NdyLq9vy-O z|D)-ac0Gasx`t0g91i3kmq6Mi=GA}8h48lj_vONX-cYc%um7KRp`HxQp&?#~d(mj7 z25w%Ib|~S<(0bz&5zB6V!IG<-|Et4iC0sAPj66h&jrLWohC(3qrLyL);2Nk1YY+N zh?`blQG<2I9(()1!^HSw@PsRh?e*j{>b~dRi^jwd%<6_7ws9#su<)wm>HAyS6}vf3 zk&jz(Acy|R*6Y_n87KJ$f`h{!u!J14f3exFy9+OJNC~HXx{XS3r{2%69 zu&sZrfaUqjkgIRUj56DMsFOA@D&(}O2oT|^*K$NUMc=h`LjRG1BCA}C+rVAS>E_$r4?9@%V1fw|G(*R%83A*#=BIUYDo6T{d%|b13*kYs{!r}ZwnX( z+Q8~_i4q`$-YTB{m+N)~j@c3b038B5U0e__prGUhQ)J!<_#=KfgL`?6p66Dw>wu{F zC_xKYnzwI|1x8Tvg3KjzV zKg4~ng?<}LL(VW1WY2W|_;@)M6gZKp#KUj1{qL?~S3y9h+NZeFjg}!OT9=)SZC9u5Ef#ZM~@!~z` zm9nHL7J!im9Wzcl*WI}K{dcGTuJK*eg?AZ}?*-ff`?K(-Ni@F-T8s~QPZR~Z$25nI z`f9z>S@9YlgH<-b-)0v({aro6G`Upsdz_8$LCct9I_Yz0!pVKz{P{On-7nLq&d31) zz5dEPMQ1RMQe=MY+nUl#l43?j;FeuW1)<1|P&#xYfY`es6b&#$vErgL?*fY_&lzHk zg8$OsjDyjq#Q8T%pP}~DzmsJFChIrO0Q|3r~4=ymTULDE267QZ&t(c3Gq@;TulJ?Fultpuk@=JV=#f(5Xc zeN_xCW?g=!Tvl%`F zorC(7hakGnqlC!w?vy8$XBkYpD*()}l|kg+z6cw5_62-(u5<{qAtYHeI;2;iU$B1# z^*-e6E4MLLz*QfYb2`+tvvZaaun8L9v(7&+4p(1JUWshR%lz&RKVY_!)2H+Uo-zgX#f; zNxi6Lg4}XX${iJ>v1nn{?ii3Ja(G_;}`usMCaW?0zI%_mANwMT~Z%l0P6Zg3y;%J&DlXCfbPb z1{6UmJjkcn87f9(Dfhq)a|aFzuFPVjMr7epeMquX;S;!A^jJwsA>z_5Ocf%8XmO;x zgS6^c!NbB+V3gl6qr>4Or`Whw>!l6M2C1hPsy?9GE~In(SZC{TWlbU~u0GA#KF^N) zqG>!m{(WC|q;!0=;7rrl$9x?)4;%&MEdu7XO=BFs?2yzXR>n4|e|ibu(O9g!)X3|4 zBK^4se?vg0M_$S*>ZzLpaY^N*Y{oYb$`45#(PS0S$fIC77A|ShBl>7YxJOtYQ%dSE zHd`YjOvmp?hZ|mtdaD?!OT zQ<4ED@&C z(I{KNMj?py7An|BW1v$NGw+tSCrN`1bu-Io$6~A`am9x>x=f)htPRu9(CMk+%a0ii zlydE)DIpE^IiJM@ASR+NSP#Lv`*Tl6K4!eC-klO0wSAeMS@~u|3U9K9n$o_Tip|)e z@NOrHMKB1Q4J+gW57>0%6c#qq<&|6uej~WAZ`G+{{Xh-vk7_Y*=SYAlvza;{GR@WT zP4H#Ov_7qI$WF3=cVQhX$EhBeCBO9g(Bo>I`yCxAjq}HNKjVt{ncf#FN=|`?jbg1) zHic3dP3?-kk-t^;2@k28*k8UH1`mN;c)9TGK(~CqFO)i*(>;|wtv?DRcr@K4jLWfW z$zC}x8%<6s(sQOg2kDN&_(U4{7Ja^>bi(ExgH~u8HP3n-9-!NDAKV>NBn=!JB z6Z_>rQd{dZG!+za-;oC10+U7I+gl;%k(_~d&{l{0E&~f2SKc9nn}SQm7z z%Y44nfWu)J@8|?HE36F__b5%57%5S8FZcN9%)0k@ml(Nl#i0+=wLn?#)Xt>x!D;c!sGSuJ zq8YiF?#-kKszVtujrWH(V#)7UMoqvHTn=hfr^zbp;k=@2UWbTDEJ!T625Dpkk7V7n z&FBpAvx{{9)bI75BqNZc8=>?`h6mR%4tkM}X;qr3D7n17Mni|!g)ieYM0B?DrET0i zV-LsepcMztFy9xdDw3mb259ErZ{Y-y=dL4Hd@B+Pe*@H0=ce)!b?p?CsQsd&HL7vy z@1wy;8lv0U6$yp_)zC<3^xbC?jmn1!Lp*%EOhSleW=!TAr`J=ppgDp9BiU}xh+hxQ z`=zh@@t**#NYG%#tei-E#m-u2dqlM2B~!5s^+u)+yh=xwyw}WH>v|tJ_XVAO47R<& zXl;AN)TcQGUXKB2WiB%Js2yKX_UUsU&`s0PnLE<~hei#3Zj^@?c&bJr*^ArR=RAoP zu2Gy(2wfD?45`W3Y}_Ph6{_$+jA0YZ3OXg1r;Z&u!*R)U*JduU#dKXbp>w1atQJ>F z*1-;yM8j=+;VR zUfsfn32v>5xZ|$|U81@*ilpUE%FHN8Fxb2?nqgixasA&umPgEq;8y~XN@w7QV`05l zcQOC38n5muGV|JIEAjGB<5TYOOljQl7|>#UA91u3Jsm{n6gf=Ct1rmvGMY6Nubdh zS(jthTUikHBam?z$y9#7VzM|K@bYM;FILfqYjm5yb}|0D>$}F(@I>TW zc-j+}-cX9xTGQuIk|g9I_MVCDL?I5=Lr(3C#l>T#L`o~>%KJ}NlvbS0p6sElybZjd z6)#-B*}aUjmjXG5nRc~ePyU(kUzUFpHF{E#ogCw8&n}i6BV`rG6gsKTPhOX$X1jiJ ze(RG{kQ02QoA_O=Sl^!8mOYNR=vy(Jdkbt2dB+~y73Jue*&CiO z(&Gm*w;nhGfpph3W1)cAp;zg#VdBh;+9~IA-9LPXk8J~A?olc+GVMhNsO?^jRKxci zSv`D}PX*+3PcZEYv`9=I--eETzsOMPS_B^nmoi zID@Lvee_%DhNc$U*H~zF5wG-4xn6DALZ6TsNelAUT^K5CDcnHI| zLf);o;G^P0Z3Kv@iZyi4z`O-EI`)vP0|w$r%e9I~w+@eQl=0{PHoXJpgC#2nxcaQt zMR;7l=~2VK^1Dry+TsuuyQ+ zex_Z$P}Jz6!i}+FKFnnJr=)#5$@`td%73x|DQx<@2!Z*4&G_d9wvf(B$%zO5!`-ic z`AGru;gS_*Z7_W|v4{OBF&00BHK-1{uW!H~AsT<}X19O-DdaUO(sYje zKWDofvhJhV0bUeChs#FfAR5`6gVL-mwMP}lMyl2oD+Pu^feTa=Xwd*0l+9E7gwNa} z8SPYViHv#T6>jtuXbWTZ6qvsM_gum^Ke|v#xyWKz(ypRUP-y4$`oa7jyyL{V4S~4{ z)897)nXam5rDLH#U^4Jm9<@CSOgXQO5PLEo=1%0%6UyWgTKhfa-k2(C zo!w^w;`D(~+e0W%p(OS|X=0RU9JfQJrvjJt4X~M14?pMr?dZS841jlFGI%{B;lN;0 z*IChAUt8aHwC6s)$s#^ClYVT}T)buaVg*b&{KApj$(v26#|_$s3ZVwaM_H*G{46ZX z@#+cg=|}7oEHW9X1?)@Gzc0DRz7pWQp)-tG-`#%9RUe|4bH-tN1zl)yFLV|AV3_H9 z%Upq;6&7uCLG^ymzJE1rcJF@`r(uo@?wgv;$SJy#-CyWvG=2k~?ohSWI9(d~EJtMX zz^ijq0#9RI-{Sp7;FeF=ll+&CP&E_J$_4u$d-~l2h~g!~rcL^xb0;x^mC=8JTL4wafN0FN>NIA= zw(Rt_-r?^#0CjJ8L3!(|>OGFOzlRk3_ft;9kPEO#E#hpEJa&*17mXciah9P$N7#R< zv-9a!I^cyJ3t(i%8Ltp@i*kJi4!z0${PF+K9C`pG{6Akr@`FX&Wm#1Sp<7NfM3JHF zN-2QA88$i_N1c!M;Z2b`y?;MJQiP;j`cE*`{cK)xQfUFo%zMBaRLibO)rloSYX&<% zya&ncK|tJjZa4BM)%Gn<{4QXoY#I9Bx=#Fo%1VHaWBsw!fJ(y&CivI0Mkd%A_+AR=5K#Q#LXSLS9`$9Bozn71t*ab2& zy16n3JUk)VxK*xGicN{JjRN#4yn%76pUP=a;C=4(%+CK^s@n|^vX+2by$@gxZ@of3 zjhcg}mOuT|y5yg?7psTbl;`^klaPr5+0braD~UpjQ^?Tpq^w7x!#-i;b4!7 z@@l_ymvKktq?`yS0*^sCLq3s9ayfqZw$q`SMCA$2Cbman7a!&t^ zOpcpMUsq$N+FJUjnufihNN-S78hf}7j?~3tz+yB(bRyVm^#-;Jh%~} zVZ#GSx~YWjNt*}{D87Xp@1295-JbckUv$rYdH-liW%9*+bPYB>nBl7H$0L(Z%On22 z4(-+gp$lwu%#(?ViPa&-0>rYq0oJd#vESc~9TXrK8SQT{e{74m?0oA9t?kwP4W!@$ zh#|8I_7U-)d!cm&&YLe|vi<0$$3QCU2!&`v9WXJ->%9T`vMM+FRpAPYM|Q8lmMG?$!rDcc9> zmn~3+Qs9c#+-FE+<4WZ0I;bD>GL9vaxOyCsDbUq z4u;&!P)i_{QGel%@K|7WW_f!E^^JVr|I6n<%T66BAResg0bB(AA0N(W(L7oNv6`7zkxanE{cd!xoT%W)?$X zQiRKQf*g?-C!IT&m#LWL(Fy=#oMlN=%PEvDU@)W_xTWVfgADea*T+@bFpBjDSQI1% zVfZL(9`7L-n|aRKl^n6bX3G~Fwhq-kY7`JM*$-hhWI!wftt*juMFf|7|BGmWhr(4J zvLo!*YxMCAHn$Z%kx6Y>1g{iYBLwNgU1p^Z&>6N-r4EpLhc9S^OjnOJ?L<9$t;I6S zQMz1z6t^IlB!V_s>6bm|vinEX1ySA+2ho{;JRp4JBx{7r^?~!XcUsnQw7BF;KX9W= zx^jveAx*5FQjlpAtspRO8u%~EZV#~RrXrY$w>m45Sxq}iO~Ke6@)sd8&_9;&J~4G} z#HN2lWiR-B+kGPKH(vpXg$ZMH0-U|-a1O7U$NoHTK0r?sxtHOj<^!1-`n4&(z`JM? z1tvjhX!4v{0oFN)M!A4kj8{?)1`M-*U=4xJij)B$lZ1`{UVKU+{3lKmJsuUWMRa7M z42A4`0AORtGvNn-(jv)%Hy+lsEgr26`Wd**lp_$CNc)kj472J}m#)QWlbhB{zN)N~ z7kcdyooWCd(skQoVLN8Fh5u%rT4l;V_!f$rS!q;AV?;F?dufMk3H_$UatTQ(Um-Mt|u zZb%gi?RP$l52!~O#0fPeFTr+cxIZGw&x5m~T>$fFff5?!(&^aqY(>9;)fsQyR zl$GO`#?1XuW23|}q-2IJZ4=cUJG$B7DQBlda7S(RF(<>>klniSNA?!Ibga=oO_5yy z>vET0UWM+&PLpUQrg?odn9gCl+mDWLZ{5rq z<#aL5URA%hSShlhg2bK6Z5B;!5fJ%RQV3D0o0ysvbY0aTb7%l zd{^lrdfQpZUKE8KI8qkwTIkLWo{2fBH`UE%r2As_P})?JyJV~-MmwFZ`Jn`gx$Nj| ze}U%!q1GqrRZNqn(TjI-XeB5za%N$2jPo<$4aP;4!gb;1G((7KJun)ygZr zGQ)S^o^3d)7qaz|M>7=0fv4^P#?VBl%6W2J^$!ARigCM3m3 zP1+;n@9-!!_3epx@HTL7^$`us%7(du^L;9tnO{94qot@&Op_3<6>6ZxPQzgfZms6& zR}rSm2<;J6$WqRHgVrxeUdsNv49T93a9FXkzNA>OhVk_R#r7Zw3a6qAANaW`85g{0r+xK3heL%%3Gn;WuB?=O% zpoi~PzI!5mWky)hVDbv{6WNW{tL`R6QcxVpn}>b;^Xib@h=HX*+>qKKzR!7a%`S|Z z3NeZb?_di3r<)ax2TkjJCWlrk3Zf+rAqub750soeXy+X-eYI}S1!g;V#TpuTMgAze zl@_;^Uu(^sE3e}B{S?h`gonNlwhM9&eQf$YozzSH!jGInZ47yc)hYCRx9p4fPTub# zbG!u^=}{k;7;@RyM`+Ak%7H3kjG-(fYQpS&`qC{*>4jFhagyoSCFd&z{zZzO8vf#u z#gZ^|fzD5Xm3o z;vhi(6!GJy_{p@RjO}Z(P{ZFq|IQc#nhD#i^rSPf${9cNk|(R=Rpuw~C)-pF+g&YWSxIEs zJbxT3mHa3R%3xwvCfs_94#u>4(;C`^&*goF3e7)iuc(K_qTj@kaMPjofckjoZ4s*0 z*-QpPP@WZPs=<93wj{+S-v&jA36#&h_|8L3_mUz7ro^AuviZqEYO&l%Orj2 z$y^F_MR||6QLw2f2rR$Fy%x2K>NS3Y5D+F$l;l>soBLjyBBOkKQ%A^RlBF%X@HiA8 za!~SPP>Sg+;l_d4x_s=kKD+6KZ9J2-2Zhf(*J1k-o`$Xl|9o;av_|tM#F)y~W6Y=m z80Z8#&uRTU)f93h;D#IF^n^XqZZIdm%MtzWTTPBb*)_LZGwVm9ciFpf{lr}{CzR(pUhrjgCK zcfqQ|5ox^h@8Q2iYb>4`;6a&pO#3Q#!P?gah6e1E=#$Da0&_w{u9^kC`G*RPCH*M{ zjvIsb3o&*g7$?qha63&0qm>d~m^CpU7a{#UUjmvLr&65Tm~9nE>Vftzuz20Sj@iqr z`)LdF<7 zwefj)j_{Cyfk6)$&SX7e=9TGpU+%|g&ALgLdfWega;3bgIZ2);k$D4eJiZX>JXg9= zp)Rc&D5`PRpHD#Bm0Yx#RjBa+TOQZ}KJ#+HXoK#ji9~fW`Ml_dEunJNZ`yF58oKmp z?8#!N7+37)^NfGh-IlG%TBZ#3$<=f4+FbJlDXVf62)zZXKdBpXir z)awxar)1DsEQu@}_$Js+!K}gX**{+{A*$j|vot3&=0ATerIe&}3w^x~7YlT{(M>%> zW^mD?B~C*5=h(&4JoOrTsxURJ68Z1TBLut~ZRu8N(JSVEHbqFo`%((s^sG;d1{ zIcrpFp8#=7?$(nw^qjYnA31GdkFQ;yjr)rD?}dvKkN{p@C2-dCpEsv_%7%cptQ#@X z_3vez#6Xj;hnGc#|L>3Mg1f-Hvg)1O-;W}j#}H70x(r&@6=o-17j=NV@fB=3;l^Pf zKq_^29rQ}B^ERMjMG9QJzG!@!JBGmDw+q4)Z~$C};yw@2WKO&CvJ$7oir4%tP%sCg zWs5?VH?iB-xr0G{y_ofqHf?CHi7&X%L!&V`- zcXi(;n6$AjKrI8U1=?^E30rgu%BI?Z;ohCv_e|qt37V!tF-Y<5fIFVG=|#2LA4F-k z+M>I%3-h`WGN7^N>Pkp|_5i;LWva+W`=NbMzvp<{0VQYqQB9IoH9j^W z){bKh7|95K{{B-8p-KKq9U0aoXqX!yB_5WkYJS8q4gy$qVE@LyqQwag=C<+{EIPb_dHt#>r_ZzyLB63gaqd@Y(*f z46+)|t%hZODu`23zR0%f4HlN%ciZV8PQLUN$H{3qII1O1AnS?nZjm3T9~^@dAPd^W z^%jIMZb4`)^>RYw9RarA57SeK5Cehf+Fwxl0U_rXBeM()5;0n+-0?Oc5Wm_{=qW&$ z4%q_$=1OSNEoey}psj}D-9kGFsA=DqU?gaN5qbyQwqyH_^OP3lA-y14G%hL%KnYqw zPK0*c?0Avk2jVQ)EpUCuf&M=byqzi2mIs^sw{FPaY|S4qU3m1I#y zY}M}jeo2(t&?gMpx}K83J{RcMKc2gqS9G4oh2#r@Q6BRFy-A05HOmtM^L%4XT7eF=<$=XI+25QnWSY2*PDXzaA zjf;EC=2Dfq^IBUpctAqjHrQldXMfrrL|c_SQ28nD`+yBJ(T3&=FaqQ8S?wRXx@3K& zFc2!Hdk@MyecTIwH+7ge1Prb_pc*TF+(5Xq5|RbGiaQk)7 zUa4!}imhzSLfmc7EjBin3g~(*!lyMal*+p0*i9R)=_UZx+t?mo&h_eyhx(qEYd#GU`@%W~oONgQUR z&>R!F(dV7~d#t&$F``NggvWtf#gi1GJL-xtCa>1pB6qj>c$86QXj+44_<0HUH~Wqw zk1+`NmQQi6X_xRI!$H!EWwv!Va>I>Tq^O~Wa8fIppX&p8$3Odnr=VD;5rI zlO=)vJw>)je9$CY*|pt)t*H9}r^I^*kw`a!{j4^BZ_}6Mn*aj^E1zzX*yD#DhBYmv zmfmgHY%>x-;ti8W5&JwGX}Mt{$jYAS{De#ZyLk`!nxN$FfHga$CY&6v1Z2C+WYiO@I3WB=Z^%;UUOhk&>0$9-F?!q~}F_ zIodSwCsZS*z$p={t0wmA`vbmA(is0ewmTCABj5v|M+un@1v_=Wqr~hlxUTwaeQ1B2 zEbt@se$R?LtDPQB(vr#k0I1;Me0=HsgMa9uj#nzGRi>8W?>VnGPYVkyhhu41C~fDK z(=BsI;eTfK8?Q`;p0cn-m0=W`4x53c2_{>J^;X@C(0=Qa{kXLkq4k$dSL>C6mgpkA zQ{27OYaPHwd#sm)^ZP9d{O*g-wtr5AOTg&F_k#pOi$@aXHFdsGb5XYTQi@abVG`E; z(;svJ%24_+ly3^Zqz+L+w?7({Mju3zDSywVefNfoiWwZ`PM{ z!MT2Mbewa+gtwc?`yO2fT&uY(#%0{UEHolK7 z`unI)iUk$DdB?Y{Z92Oq{j(<#A=hN2hibf43jno!77Yn7Q^QKZ}N1v6`A8 zi6P9VJ2XqbzZ)iyrimYFM}5*4ni@s7Tjb3yWFjQY3AfsEw-joffk`|RNSl2Nh8!z@ z#PJ1QxqfALw586;C+99V;@C-n;&e|-lD{Y@{kWKB1ut*HU72fKMVn;2Qad-+#Mmrx z6X$Jqb1Jg8{Lh4E!$gz+YFt~My6X3*z<5G`+knwFcvE?jTIt7s=B5l4N$CZTmdK_w zuvw|eKeLsUz+b^c3J4}&o-aNpN>Q% z?f=^AdEg$T!*9Wi)4I+XzK)0aW=#YQmt+Jw#VUIJy(rRREL`t+I{1qI8MApSI#24b zur{`bNpIP*;M_#;V9AB7R%dU4U2|UsKHlK$d0tdE!j-wp4l{13g)%e?ii>0 zGHj~PY`;$u&Nrs65mS{b0gvt|UHHawE9iw%!R2Xz8x}P4JzR5Du&N(8j&$nLr!`YW zo+g={$u>{0O7rE*Z|=+v0Yo4Ce;In z{WLxwTr&T9;bRV9u1nVh4>7a=hewM1wuc#f(gzPOI6`Jk*fe!h3MszX6YI_sHncn@@x#tUeavvJ&dUC1a+4bV?# i)7MErEV7z%;6GDT+(G-p9|eCg0D-5gpUXO@geCy>1K9ik literal 0 HcmV?d00001 diff --git a/Help/attachments/enum/graph.png b/Help/attachments/enum/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..121e8d5f78be6a8f31c05d69046e0ebea29b081f GIT binary patch literal 6099 zcmaKPWl$VIv+V{6?he7--GVGmkVOLocXtw8HaG;g#U;2q3qgXryL*7(?sm!d>fXBV z{dhGsbE>*}dhB%fbhwI=EE+N~G5`QTllvs4_J(C|Jq+>v+n6#z;tv3z<628fs>n%7 zQaHIdT3Fke0{|XNQCjW-b20Ox*_Mlk`*J~EBLi#H=4QhKS>}#j!Xh$^;qh(Mi-{_^ zR)ldP@^NOes`6&E)WYq+hqlw(m|HLKsrRdE_T$Gry}b0+d#Lk|EcL3ivE|L%50Vsncasd?R05PX)7dKe3PXG!TD2EWz_dhUz zx;?{}w^QoBT*v^7(A}={0Tfm5obCYprvN~jHDCpa|Ms#HFd_x` z$I!le5&?qj?T*91{jD8vIlJ)R6<_kS!vQPwFdO_YlhL>^N6H9RT+gz)+^}!}%$vqN z5wo{j0~pW1b@=70%?AOjrT}j0B{RU@&j$`j056!0f^1t%!Mk;SiCEF^ugotkd+q)* z02KhmJLxd43nY#3-+|U0Y?Fl3bJJy9k=(0Bf}PD#j-&kcl4-n#c2*k?mmufyY;)jXs9#PmSq$x};Y&ae zDpD$n=Z5*Fp^ity$HSytAE?LfGF_dxT=|?hop@ciT^rA;Z|cu$Z=hG4m%QiPSMx{{ z!bM6`s5}(9S?+mo@cJl97>vjjtt#Le>Z9X=xMB58!>SQk7QJVzdsds>rT)Y2$!Gp% z6N8?)o}}JA8X8&y5EXq(eoBE&pFhbOB2YXh0#mTD_ng|UT2O{ zU%obcy!VO=k&L<{SRhCTU5;+E8#eOPLmJH+WL;xFk~V*9De!Lcc5YLsk}+t!(rA_Q z_AXif+HsM2le6U=M|pxV(#_Gz#l`(mV2;m#Ta_#Ih12EWslK27aeS9srtZP8{&(qk ziJ$rd8$bKCq@B2j>c-wCZKZj1(sS7z@0{VtVPyM0pB108Zj=2A`4PGsL0xDr)n_I^ zSSPC#43Pw0-ZY1MH8qb(edGQjAydk?)Yod!z67M&$9aqyr-!fSPW+@?f=>{wVD`9n z-Hl|-7sTx9l&}$1T2*sST4zrrZ8;=HW9xTB4vWt&s23FNg&bu9#WT52DzuLa8XBkD zh4g=Bn`Su=fV_P?ElQ%3OjAk|NRzHp)6>Zu6oht!(OEVeL)^bjwoFRhb^0Q$#!P>^kWsLt^K`BLYK;K6qZRK!w=Cj+JI@pOi18TWZz38n*>P6@@@p=0S zdu_;AD*7IEH*MXeBTa@=%B>CZF?y9CTf^+%UA0Btr%R@Sw9Omi>m(h7b~8rs22ICw zhsjy3*jU(`wS6l7JdrlG;1}rJnhkplYY(|I@19}+t;)*1Qq=KuNgoDoYt*A$D+Y1e ziVntcvlZr$W-ob;Z1ZhbyldvJDm=H$!3y4o)6k2XWm2TfH*aYVXA0 z)G(>kVvr?;Ok1m+n+$YBn?2rt*tWMIf?z>YeC31KkM=*eYS@*tzfWi_DjCnsLYViQUFId^EB%dWzvW{a*Z_Um=IW27aull`q+z`Ra#dqV;qs-yRSr=&K+0 zW4X{aZ~E2F;QXLt)9KbF1lUC|L?8=UfRJht&zXVS?(A!7>XYvF{wmF9F()CP-LAg_ zY~TV;Mqs}vz!KsDaLZv3cK}Bba2)0^)hh4*(7%gCG8Q`kKHt6?!5XW;Dx3u}420PH z4Y6L3`htZeh2tzH5zCX0y)V71LWm2L$Jq&J4q=kM&V@`KS@G6md_-9dUhDg0{KSF5 zG5p2cj>nDA9oHR?UnWm1LA*}MR&rU2UMg9lQ5GEi!X3!k?cFyW39ATE#2FzQv1N%X zw<`~}o3gX_AbGm@4Hv-h(-D}O8PRqrh8fDy4`+EGo*B5Thw)3_L%{PrM!^SB5DjL( z=jj>zg)QO{P6|#r!4IGb^$2?_gPJ>!&WyaGR3wuql`3;8oiqfRs0!JEtR|5pgDYcy zep2I7g?#QTvm;AaI~IJo>LG1VycUQmOG{QZm}@R2%}c1%E!L`7x8Sg7vgk2kF*dQ0 z7tFMsv;J){=xANsuDVq3N4G+DFH(le!7tJpf_>~+PkrGB3sh_pO#UPz$ULd^h5`6e z%3`l#dQn}_-*e$EJOY%2qSWOjzAhR6TpfbMGy6^{k{PzK!TWL(aXn!?EfEU6QN>WQs*iC+ zkaDsTtWqM6Ddk};Au;+-{1WWi?F$>Jo6G8#ef4x*g&{?97K^*b_{^F{1{}35uPO9gFRhZI+{)gSy@8OzJ|#6!$GtgYx;P z75J}E*G3-YHU>~ut?y4?KYbNQPALW)otgB?#Y=FXDPY)WRD0*j=(DqNaB1jv=uP4d zjfC>M$=@iJd5ti}_16p@2AGm=UR|f~+W_2jFRNO2psCn&UFd6PrgPOPJ@S zsTxiwTG7^%d_-G~UhDbi@JT7W1Iy=DlpKb8bI_084gV$?AwZBu(9cO!;M11c z#?to5mYk@WZ;FS9|3XLlz+M+vapQYO$VQ6Fa2)ccVqBT5uN0^!zZYqX1Un&~R4pbS z#Z1k-YFHnFp@FED&k&ac`&l?9Q?)_Z?;r@87Sfy+l2*7Yr_YLGuS<%tYSbq1j2)O9 zk{x9gWv)1uLYL{lxm+C!y=pA2H-KtXqcom6n*q0-Z+>wnM6?_#+;)>;W!0^{7j5us zeJR|CO3Ab?|EYwmFo+(o9NV!|fDbI)Y`NH4%4`8L*A7e+?4pRxxHcpJC-FW)J zGx4G!56^Pj(=74&*s|)p`Py?G|4YLs!&}|#cYW>}r=UA#R2C@qTl6wTA#CDRb_@m-t-jAcb zyyi58zSVt7S=9Oz-rioSVZ=1?*+Qzo4h@M&25Q=ZtL(#9FChTn1GAU|6+leEzW;UL zkw8?G{A=WbKkr*v^WH>3RtoU?ujRBACA>+HoIYuP1prWR{`Gf&v<$*GA;LE~kTk+7 zJUk9IACDQ8)0>)@oRs)ykEP>GRV&?jqJA*(g^6W?rcm9yPQIH>!2mq7u6+3IhMM5w z-?;|lz{zqq*+-84$T$I1Vi*OK6X*z$Y0|#rifEIH5RX8xV09C#f?h_=l9^kLaO~nA zS{uvBFH!Jn+>A*ZN1f5h<+cgUYJzDmzzN9{+TZIUw|l34w|CPb=%$h4Vb~ie#4wcF z!Lj8MwaEV;yu%fUxDLD=6sS>P%y7U!yJm~3uja0!D|}yEe7<4tP&m15ajKv`hu+a; z`)v1Bz{AH#i7zp;JiPA6=D5(-BQ1kd?}JbeiZayY8fWB} zdif>zFTEmpyN8{SQhX%25KKqsUjKlO2Eg;q`WqIvciJX}UM$KEz3qt&@{?gFJj;jm z{saOqA|!aqCsCp@rB!Klb&*)=%m9$fPgL@1zNUAd=*PB>2~F-yLL4Jc-|?;dG4eFw zcC2xNXQ~Vzw_ll`3$R^%3^IGpA4!9`!vTWpNx-LYF}$C-+kXu&wzkOVXur_oXBX;&)7N+qm?}s9A7)M+z#8s!k7> zFGsUqrw815yH9QeE!d7vilG1OhwV+D(O>@t2=~a4dZIct2syufkrT$E&l+J0Oj5Am z?MvwmpRjS$zyC&-UVl2z!)+fh-|KO_eVYCmxeiyh#=s>`xi6g6(n)i6pZ!ZN1ujUF zvOL=o@9pIVODQqqHNvLic$I}8(8>SUlLx4UtK%xq9T}e4*>Bh{?=2|MDyfc)JV=vm z_&4lgdov~p1lwr-KQE3SiQ$>RU-ODGR)Af^U=m@JbtmM!;=VSRTtW8FU~#raF)HT2 z^_YUp@Vfl8XUCc3r8TeXeoPIPA6Vj*Y6qMB+s>QW|DbWnKWVV^^BW|UOB7q+#cLq` zXYP*7B&1ND9*2d!C}$|D==WSLZ*?UIEX19>zI{hPQc(^!)mq;_u0jFmn02Xu{n5N-X4V6s z^B5VE_TipXot|B^4)9MZ;CQ4{F`AyGMZY z8h3Izz0qZK3mK{^FIRcO>T@V0F6sg1Cg_WCI-9r@c6m4h zLHu5QwiU<8i+-7gZ5DTG2`LjVsHkc{!W#s@4xo&@wiCaFw@}K3+2F&|1k|X|bA$jp z=k?(#L&2y0G1XeXp3l(^W!pxN48PVzB=!~G(+V6En>IPdFBZ8ia5eTl{Q_PzGIxY_ zAnYNz34^q(QbJGGM)=(uR1Xu&56Rc=7@35{B`mvyKV!V=9JeidJZh%d9LvEj-r+iq zIMO(QQP?cA?$u?j&_zd$XnJu(6|~OB#%o%-l)VMIe?z$BOXi2560aR2JLZ6!)2q7I z=41Z}9?M(%#=Q}B6gYRcmFg0A8oR1u=5V)y-=pT=FA^Hcb>S`-X%v#x%q~>6t#g{O z-w1hkR2(P$Nt2SM>@C(M)|7hzZ9V(6f7Bj4m+uf+T3cwgWj6?Ke;)nE?EkQortF_f zVaIBmTC$D{M1-!5mkQ99Vg7H9v;LVbdypFD7*k8s@Xh@{X0F2_mKkqK{~b~P;|QuS zwWZ4S!rLrl2bLNcZ{}zJC*J0+IN2alVChmMg)+I5UN^9z4OmiU)8Xq<8EQzX`!?*P z@(T4Egu?cNeIG32@zL!fUsll%h}%5c41`@B#tK*?I7Or%UkR1_Pu|&)OkO=PE-|n0 zc(r+m@Cw|J(c3qa|7n7|id1yrB&Nj<#|)Rc+Z36FpxMX!JMz~8XJvVkx>G(3M@0Cn zLV11kZ_i8w6a_xeeTc@4QksIT-a$WVMlkbyP8RR;?i(PIWcmoh{_X6*XS2CCLi7Df z%{?1&noUKUuKAwqKG`jIoY#-S*)jutLr3F$wlp1`xfeVk*YA6O&6?-CT%Gx0>h{8S z$n%---v!)>!0RDZZA5ex(SZP{W!YkuRf0Gm?MAoftp&=!_Hjie)XLuFS$-QxWSbdP z_j`{1LUp(IO+3Z{^ZJhyQpU1%XYCo4_NX#cW&>E+L`ChUK%r12E~vn0;C1%5CgGaY z#xG4>OIrLcD}BE9tW9%mr`w+FH*7&M6JFr&o#BY=e*0BVM{5)l)6JyKj)MfhQg~q(ODXxt?e!XcFI?Oca5#(c& zivpVE98@|~2rX!&*7f$a8Yy6(NVgs;B?k&cy&LV(39hw!cp?O^n{`I329=b-D`g7H zvZT_bgPfqR6w0tbWV?m~?VKrs4a|w>C+42ZSY<`$debm5D+K7M?jLr2BU~WHy6raX z2C_yvu|J1t)p#7jR88akS3;fBhtgh*FRA+^KkPcLqJxfojKZVW&Nx2J=Okf#DLLbW z6*oQnI%|_?QP1zu?MlC3NtN0~`cr^4;GQMCKq21+Z^ox0>p=d9Hr>qFnaEND4efe1 zZ2V(}Gk!9+G?DUK8i^N=V) + + + + + + + + + + +

    enum general enumeration tool, can be used for a variety of combinatorial problems

    +


    +
    +


    +

    Method enum implements a basic backtracking search suited for a number of counting and

    +

    optimization problems. For specification of search criteria a boolean-valued Function 

    +

    has to be passed.

    +


    +

    Some Important Issues Regarding method enum

    +


    +

    The method applies to Integers indicating the recursion depth.

    +

    Due to the nature of combinatorial problems with an often rapid growth of solutions

    +

    and/or enumeration steps with increase of size, it is recommended to start 

    +

    examples with low numbers to avoid hangs.

    +


    +

    Integer::enum (pool, function, evalAtZero, type, order, maxNum)

    +

    +

    Returns solutions of the problem, which is defined by function,

    +

    as an Array of SequenceableCollections (size = receiver).

    +

    +

    pool - SequenceableCollection of items to be considered for 

    +

    possible solutions.

    +

    If type equals 0 the same pool is taken for all indices of possible solutions,

    +

    if type equals 1 a SequenceableCollection of pools might be passed.

    +

    The existence of an additional type arg is necessary as it might also be desirable

    +

    to consider SequenceableCollections as single items of possible solutions.

    +

    +

    function - Boolean-valued Function to be evaluated at currentIndex. 

    +

    For many applications it is not necessary to evaluate at index 0

    +

    (so per default evalAtZero set to false), the Function is not evaluated

    +

    and the item is supposed to be considered as first element of a possible solution.

    +

    +

    From current state the Function is passed the following args to specify search:

    +

    item - Current item to be checked

    +

    currentIndex - Current enumeration level, 

    +

    between 1 (resp. 0 in case evalAtZero set to true) and receiver - 1

    +

    currentCol - Contains current collection of items already chosen

    +

    at indices up to currentIndex - 1, for efficiency reasons 

    +

    length of this collection equals receiver and items indexed at 

    +

    current or higher enumeration level might stem from earlier enumeration steps.

    +

    indexCol - Current collection of indices (of items from pool) already chosen, 

    +

    for efficiency reasons length of this collection equals receiver and indices at 

    +

    current or higher enumeration level might stem from earlier enumeration steps.

    +


    +

    evalAtZero - Boolean. Determines if function will be evaluated at index 0.

    +

    Defaults to false.

    +

    +

    type - Must be 0 or 1. Determines if pool should be taken for all items (0, default)

    +

    or specified per index (1).

    +


    +

    order - Boolean. Determines if search should follow order of items given in pool

    +

    or a search order is randomly chosen. Defaults to true.

    +

    For search of a single random solution one would set order to false and

    +

    maxNum to 1.

    +

    +

    maxNum - Integer. Maximum number of solutions to be searched for.

    +

    Defaults to inf.

    +


    +


    +


    +

    Example 1:   Basic enumerations, Subsets

    +


    +


    +

    // Listing all tuples from a given collection.

    +

    // Note that this kind of complete enumeration 

    +

    // can be done with method allTuples more efficiently.

    +


    +


    +

    3.enum([1,2])

    +


    +

    -> [ [ 1, 1, 1 ], [ 1, 1, 2 ], [ 1, 2, 1 ], [ 1, 2, 2 ], 

    +

    [ 2, 1, 1 ], [ 2, 1, 2 ], [ 2, 2, 1 ], [ 2, 2, 2 ] ]

    +


    +


    +


    +

    // type 1 for specified pool(s) 

    +

    // receiver must equal size of passed pools

    +


    +

    3.enum([[1,2], [-1,-2], [\a,\b]], type: 1)

    +


    +

    -> [ [ 1, -1, a ], [ 1, -1, b ], [ 1, -2, a ], [ 1, -2, b ], 

    +

    [ 2, -1, a ], [ 2, -1, b ], [ 2, -2, a ], [ 2, -2, b ] ]

    +


    +


    +


    +

    // strictly monotone tuples 

    +

    // note that function is evaluated only for i > 0,

    +

    // so no problem to write i-1 

    +


    +

    3.enum((1..4), { |x,i,col| x > col[i-1] }); 

    +


    +

    -> [ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 4 ], [ 2, 3, 4 ] ]

    +


    +


    +

    // Above is equivalent to the task of finding all

    +

    // k-subsets of a given set of n elements.

    +

    // The results are lexically ordered.

    +

    // For an arbitrary pool, not necessarily numbers,

    +

    // you can use the index collection arg within the Function.

    +


    +

    3.enum([\a, \b, \c, \d], { |x,i,col,icol| icol[i] > icol[i-1] }); 

    +


    +

    -> [ [ a, b, c ], [ a, b, d ], [ a, c, d ], [ b, c, d ] ]

    +


    +


    +

    // The number of k-subsets of a set of length n equals  n! / k! / (n-k)!

    +

    // You might want to check before a complete enumeration:

    +


    +

    ~subsetNum = { |n, k| 

    +

        var p = 1; 

    +

        k.do { |i| p = p * (n - k + i + 1) / (i + 1) }; 

    +

        p 

    +

    }; 

    +


    +

    ~subsetNum.(18,5)

    +


    +

    -> 8568

    +


    +


    +

    // In principle search for tuples with certain features (not only subsets)

    +

    // can always be done with using allTuples and filtering out afterwards, 

    +

    // but this is only feasible for small n.

    +

    // E.g. n = 18 and k = 5 requires calculating 1889568 (n**k) tuples first. 

    +

    // Furthermore method allTuples defaults to a maximum number of 16364 (2**14).

    +

    // So (18**5).log2.ceil (21) gives the exponent of 2 to pass 

    +


    +

    { 

    +

    ((1..18)!5).allTuples((2**21).asInteger)

    +

    .select { |y| y.every { |x,i| (i == 0) or: { y[i-1] < y[i] } } }.size.postln; 

    +

    }.bench

    +


    +

    -> 8568

    +

    time to run: 6.6191733989999 seconds.

    +

    6.6191733989999

    +


    +


    +

    { 5.enum((1..18), { |x,i,col| x > col[i-1] }).size.postln; }.bench

    +


    +

    -> 8568

    +

    time to run: 0.10966498400012 seconds.

    +

    0.10966498400012

    +


    +


    +

    // Tuples without repetitions -

    +

    // keep in mind that passed collection is of full length in each step, 

    +

    // so we have to restrict to the indices up to i-1.

    +

    // Writing col[(0..i-1)] means that a new Array is generated in

    +

    // every enumeration step. This might be a bottleneck

    +

    // with a huge number of steps and could be optimized.  

    +


    +

    3.enum((1..4), { |x,i,col| col[(0..i-1)].includes(x).not }); 

    +


    +

    -> [[ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 2 ], [ 1, 3, 4 ], [ 1, 4, 2 ], [ 1, 4, 3 ], 

    +

    [ 2, 1, 3 ], [ 2, 1, 4 ], [ 2, 3, 1 ], [ 2, 3, 4 ], [ 2, 4, 1 ], [ 2, 4, 3 ], 

    +

    [ 3, 1, 2 ], [ 3, 1, 4 ], [ 3, 2, 1 ], [ 3, 2, 4 ], [ 3, 4, 1 ], [ 3, 4, 2 ], 

    +

    [ 4, 1, 2 ], [ 4, 1, 3 ], [ 4, 2, 1 ], [ 4, 2, 3 ], [ 4, 3, 1 ], [ 4, 3, 2 ]]

    +


    +


    +


    +

    Example 2:   Melodic Shapes

    +


    +


    +

    // This follows an idea by Fabrice Mogini

    +

    // Given a sequence of pitches, find all melodies of same shape,

    +

    // here just understood as up-and-down movement,

    +

    // using the given pitches without repetition.

    +


    +

    // The Function has to check whether

    +

    // 1.) there are no repetitions

    +

    // 2.) the difference to the last item is of same signum as in the original pitch sequence

    +


    +

    // keep in mind that, as always, passed collection is of full length in each step, 

    +

    // so we have to restrict to the indices up to i-1

    +


    +

    ( 

    +

    // assuming no pitches repeated

    +

    m = [60, 65, 62, 69, 71]; 

    +

    d = m.differentiate.sign; 

    +

    f = { |x,i,col| col[(0..i-1)].includes(x).not && ((x - col[i-1]).sign == d[i]) }; 

    +

    m.size.enum(m, f); 

    +

    ) 

    +


    +

    --> [ [ 60, 65, 62, 69, 71 ], [ 60, 69, 62, 65, 71 ], [ 60, 71, 62, 65, 69 ], 

    +

    [ 65, 69, 60, 62, 71 ], [ 65, 71, 60, 62, 69 ], [ 62, 65, 60, 69, 71 ], 

    +

    [ 62, 69, 60, 65, 71 ], [ 62, 71, 60, 65, 69 ], [ 69, 71, 60, 62, 65 ] ]

    +


    +


    +


    +

    Example 3:   Partitions of Integers, Scales

    +


    +


    +

    // list all partitions of a given integer a into n summands

    +


    +

    (

    +

    a = 10;

    +

    n = 5;

    +


    +

    // storage of partial sums

    +

    // ith element will represent sum up to index i-1

    +


    +

    p = 0!(n+1);

    +


    +

    // Function should also consider case i = 0

    +


    +

    f = { |x,i,col| 

    +

    var order = (i > 0).if { x >= col[i-1] }{ true };

    +

    p[i+1] = p[i] + x;

    +

    order and: {

    +

    (i + 1 < n).if {

    +

    // check if partial sums are not too large

    +

    (n - i) * x + p[i] <= a

    +

    }{

    +

    // partition check at last index i == n-1

    +

    p[i+1] == a 

    +

    }

    +

    }

    +

    };

    +


    +

    // true causes check also at index 0

    +

    5.enum((1..10), f, true); 

    +

    )

    +


    +

    -> [ [ 1, 1, 1, 1, 6 ], [ 1, 1, 1, 2, 5 ], [ 1, 1, 1, 3, 4 ], [ 1, 1, 2, 2, 4 ], 

    +

    [ 1, 1, 2, 3, 3 ], [ 1, 2, 2, 2, 3 ], [ 2, 2, 2, 2, 2 ] ]

    +


    +


    +


    +

    // in above Function the given integer and the number of summands are hardcoded.

    +

    // For a general purpose tool better make a function constructor,

    +

    // also build in an arg that determines if solutions should be ascending or not

    +


    +

    (

    +

    // Function to make boolean value Function depending on sum a and number of summands n

    +

    g = { |a,n,ascending = true|

    +

    var p = 0!(n+1);

    +

    { |x,i,col| 

    +

    var order = ((i > 0) && ascending).if { x >= col[i-1] }{ true };

    +

    p[i+1] = p[i] + x;

    +

    order and: {

    +

    (i + 1 < n).if {

    +

    // check if partial sums are not too large

    +

    ascending.if { x }{ 1 } * (n - i) + p[i] <= a

    +

    }{

    +

    // partition check at last index i == n-1

    +

    p[i+1] == a 

    +

    }

    +

    }

    +

    }

    +

    };

    +


    +

    // Function for listing all partitions of number a with n summands 

    +


    +

    h = { |a,n,pool,ascending = true| n.enum(pool, g.(a,n,ascending), true) };

    +

    )

    +


    +


    +

    // partitions of number 10 consisting of 5 summands

    +

    // monotone tuples are demanded (so reorder of tuples is neglected)

    +


    +

    h.(10, 5, (1..10))

    +


    +

    -> [ [ 1, 1, 1, 1, 6 ], [ 1, 1, 1, 2, 5 ], [ 1, 1, 1, 3, 4 ], [ 1, 1, 2, 2, 4 ], 

    +

    [ 1, 1, 2, 3, 3 ], [ 1, 2, 2, 2, 3 ], [ 2, 2, 2, 2, 2 ] ]

    +


    +


    +

    // partitions of number 12, taking order into account (not ascending),

    +

    // lists all possible scales of a certain number of pitches,

    +

    // given as interval arrays

    +


    +

    // this gives all scales of 7 tones with stepwidth from 1 to 3 semitones.

    +

    // Result contains rotations of interval arrays that are different,

    +

    // e.g. major [2,2,1,2,2,2,1] and dorian [2,1,2,2,2,1,2]

    +


    +

    x = h.(12, 7, (1..3), false);

    +

    x.size;

    +


    +

    -> 266

    +


    +


    +

    Example 4:   Graphs

    +


    +


    +

    // undirected graph with 9 nodes

    +


    +

    attachments/enum/graph.png

    +


    +

    (

    +

    // graph represented as array of possible successor nodes

    +

    g = [[1,2], [0,3], [0,3,5], [1,2,4,6], [3,7], [2,6], [3,5,7], [4,6,8], [7]];

    +


    +

    // Function for finding unused nodes to be connected

    +

    f = { |x,i,col| col[(0..i-1)].includes(x).not and: { g[col[i-1]].includes(x) } };

    +

    +

    // search for all paths using each node exactly once

    +

    9.enum((0..8), f)

    +

    )

    +


    +

    -> [ [ 1, 0, 2, 5, 6, 3, 4, 7, 8 ], [ 4, 3, 1, 0, 2, 5, 6, 7, 8 ], [ 6, 5, 2, 0, 1, 3, 4, 7, 8 ], 

    +

    [ 8, 7, 4, 3, 1, 0, 2, 5, 6 ], [ 8, 7, 4, 3, 6, 5, 2, 0, 1 ], [ 8, 7, 6, 5, 2, 0, 1, 3, 4 ] ]

    +


    +


    +

    // give only one random solution - here path of length 8

    +


    +

    8.enum((0..8), f, order: false, maxNum: 1)

    +


    +

    -> [ [ 0, 1, 3, 4, 7, 6, 5, 2 ] ]

    +


    +


    +


    +


    + + diff --git a/Help/kitchen studies.html b/Help/kitchen studies.html new file mode 100755 index 0000000..ec498d3 --- /dev/null +++ b/Help/kitchen studies.html @@ -0,0 +1,1090 @@ + + + + + + + + + + + +

    kitchen studies source code of the corresponding fixed media piece

    +


    +

    Part of: miSCellaneous

    +


    +

    See also: PbindFx, Buffer Granulation, Live Granulation, VarGui, DX suite, DXMix, DXMixIn, DXEnvFan, DXEnvFanOut, DXFan, DXFanOut, ZeroXBufRd, TZeroXBufRd, ZeroXBufWr

    +


    +


    +

    In 2016 my interest in granular synthesis was focussed on the potential of sequencing arbitrary effects and effect graphs on single grains. This is an application of the class PbindFx, which I added with miSCellaneous v0.14. As the possibilities are countless – an arbitrary number of effects can be applied on each grain in an arbitrary way: in sequence, in parallel or in any graph order – I started experiments with combinations of at most two effects and sequencing their parameters. At the same time I wanted to share my experiences and document what I was encountering while composing a piece of music. I thought the best approach for that twofold need would be a sequence of small pieces in once, each of them using different effect processings per grain. A piece of such form would not be totally typical for my usual compositional practice, as I tend to favour longer forms with a few contrasting types of material combined in a developing relation, but nevertheless an interesting challenge. As a sound source I took the kitchen sound of five seconds which is already contained in miSCellaneous lib since version 0.7 and used for examples in the Buffer Granulation tutorial. 

    +

    For the fixed media piece kitchen studies the audio, resulting from the six sections of code below, has only been cut and slightly mastered with a bit of equalization (as many random components are included, the output will of course vary from one evaluation to the next). Each code section delivers a mixed control by gui (VarGui) and code snippets (Patterns), which reflects my personal experimental preferences with the concerned sounds and might serve as a starting point for the reader's experiments and modifications. Compressed versions of the original piece as a whole and its parts can be found on my website http://daniel-mayer.at, a further documentation of the compositional process will follow as publication in the artistic research database Research Catalogue (https://www.researchcatalogue.net/profile/show-exposition?exposition=324609).

    +


    +


    +

    WARNING: 

    +


    +

    1.) Be careful with amplitudes, especially with buffers you haven't granulated before !

    +

    Also keep in mind that a granular cloud moving through a buffer can suddenly become louder – this is especially the case with the one percussive sound contained in the used kitchen source sound. Moreover other controls than amp (e.g. buffer position, trigger rate, effect parameters) can cause a raise of amplitude too.

    +


    +

    2.) I haven't used below setups for live performances. Although all of them work stable for me as they are, in general hangs can occasionally happen with pattern-driven setups. Often this can be tracked down to sequences of extremely short event durations (and/or long grain durations). Where this can happen as a side-effect, thresholds can be built in (e.g. a parameter maxTrigRate). 

    +

    Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended – and if more complications are involved: testing without sound first after saving your patch (generating data with a single Stream derived from a Pattern), might be a good idea.

    +


    +


    +

    NOTE: 

    +


    +

    Running the code examples: First run the code from chapter 'Preparations' - i.e. start server with extended ressources and evaluate the following block of code. Then you can run the example code of each part (but not in parallel). See the comments of 'Part 1', many of them explain principles, which are used in all other parts too. Similary, gui conventions are pretty much the same for all six parts, see the note on common VarGui features below.

    +

    Types of variables: For employing the VarGui interface environmental variables and PLx patterns are used. With VarGui every EventStreamPlayer derived from a passed Pattern is run in a separate newly generated Environment, where variables are being set and Streams from Pfuncs and PLx patterns are reading from. See Event patterns and Functions, PLx suite and VarGui. For certain live replacements though, environmental variables in topEnvironment are chosen and for the sake of clarity some interpreter variables are used too. As a result of these two exceptions the six code blocks, as they are, cannot be run in parallel. As each one is producing dense and rich sound structures it was supposed that combining them in realtime would not be the first option anyway, but it could of course be done by rewriting these variables.

    +

    Buffers: All examples below expect mono buffers like the delivered kitchen sound. Buffer paths refering to the included sample suppose that you have installed via quarks or moved miSCellaneous lib into the user or system extensions directory directly (not into a subfolder), if not so or you have moved the sample file somewhere else you'd have to change paths accordingly.

    +

    Versions: For the published version of kitchen studies I worked on OS 10.6 / SC 3.6.5 and OS 10.8.5 / SC 3.8.0, slight differences in sound might occur with other hardware, operating systems and SC versions.

    +


    +


    +


    +

    Preparations

    +


    +

    // start server with extended ressources

    +


    +

    (

    +

    s.options.numPrivateAudioBusChannels = 2048;

    +

    s.options.memSize = 8192 * 32;

    +

    s.options.maxNodes = 1024 * 4;

    +


    +

    s.reboot;

    +

    )

    +


    +

    // loading the buffer (maybe you need to use Platform.systemExtensionDir instead)

    +


    +

    // defining SynthDefs:

    +

    // 'pos' for single grains

    +

    // 'posPlay' for moving buffer position

    +

    // fx SynthDefs for PbindFx

    +

    // 'leakDC' for leaking DC from summed grains and limiting

    +


    +

    (

    +

    b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav");

    +

    // This searches the most likely extension places for the miSCellaneous folder.

    +

    // In case of an extraordinary install situation or a removed sound file, pass the concerned path.

    +


    +


    +

    // \posPlay is the synthdef for one grain

    +

    // args pos and posDev are to be read from a bus, played by a LFO

    +


    +

    // arg pos is relative between 0 and 1

    +

    // arg posDev is absolute (max absolute deviation in seconds from pos)

    +


    +

    SynthDef(\posPlay, { |out = 0, sndBuf = 0, granDur = 0.1, pos = 0,

    +

    posDev = 0, rate = 1, att = 0.002, rel = 0.005, pan = 0, amp = 1|

    +

    var env, src;

    +

    pos = Rand(posDev.neg, posDev) / BufDur.kr(sndBuf) + pos;

    +

    src = PlayBuf.ar(1, sndBuf, BufRateScale.kr(sndBuf) * rate,

    +

    1, round(pos * BufFrames.kr(sndBuf)), 1, 2);

    +

    env = EnvGen.ar(

    +

    Env([0, amp, amp, 0], [att, granDur - att - rel, rel], 0),

    +

    doneAction: 2

    +

    );

    +

    OffsetOut.ar(out, Pan2.ar(src, pan) * env);

    +

    }, \ir!10).add;

    +


    +

    // posRate of 1 (given by posRateE and posRateM) means

    +

    // pos movement through the buffer with original velocity.

    +

    // buffer segment is determined by posLo and posHi.

    +

    // posDev and pos movement do not depend on buffer length and size of buffer segment !

    +

    // (posRate does, but pos is then mapped to the buffer segment by .linlin)

    +


    +

    // there are four types of movement through the buffer, determined by the arg 'type':

    +

    // O: forward

    +

    // 1: backward

    +

    // 2: forward and backward

    +

    // 3: randomly with cubic interpolation

    +


    +

    SynthDef(\pos, { |out = 0, sndBuf = 0, posRateE = 0, posRateM = 1, type = 0,

    +

    posLo = 0, posHi = 1, posDevE = 1, posDevM = 0|

    +

    var pos, posDev = 10 ** posDevE * posDevM, posRate = 10 ** posRateE * posRateM;

    +


    +

    posRate = posRate / BufDur.kr(sndBuf) / max(0.001, (posHi - posLo));

    +

    pos = Select.kr(type, [

    +

    LFSaw.kr(posRate, 1),

    +

    LFSaw.kr(posRate, 1).neg,

    +

    LFTri.kr(posRate, 1).neg,

    +

    LFDNoise3.kr(posRate)

    +

    ]);

    +

    pos = pos.linlin(-1, 1, posLo, posHi);

    +

    Out.kr(out, [pos, posDev])

    +

    }).add;

    +


    +


    +

    // leaking DC and limiting summed audio of all grains

    +


    +

    SynthDef(\leakDC, { |out = 0, in|

    +

    var sig = In.ar(in, 2);

    +

    Out.ar(out, Limiter.ar(LeakDC.ar(sig)));

    +

    }).add;

    +


    +


    +

    // this Function determines enveloping convention:

    +

    // absEnv = 1 (true): attack and release times in milliseconds are taken anyway,

    +

    // 'overlap' is possibly overriden.

    +

    // absEnv = 0 (false): attack and release times in milliseconds are taken only if

    +

    // their sum is smaller than grain duration (derived from 'overlap' and 'trigRate'),

    +

    // otherwise they are shrunk and their relation is kept.

    +


    +

    d = ();

    +


    +

    d.attRel = { |dict, granDur, att, rel, absEnv = 1|

    +

    // times in secs

    +

    var sum;

    +

    att = att * 0.001;

    +

    rel = rel * 0.001;

    +

    sum = att + rel;

    +

    (sum <= granDur).if {

    +

    [att, rel]

    +

    }{

    +

    (absEnv == 1).if {

    +

    [att, rel]

    +

    }{

    +

    [granDur * att, granDur * rel] / sum

    +

    }

    +

    }

    +

    };

    +

    )

    +


    +


    +


    +

    NOTE: 

    +


    +

    Common features of dedicated VarGuis 

    +


    +

    The slider section always contains two blocks, the lower one is for parameters of the buffer position synth and the upper one is for parameters of the PbindFx. Within the lower block the relative buffer position is determined by parameters 'posLo' and 'posHi'. As the percussive event within the the loaded kitchen sound appears around position 0.3, most position defaults describe a relatively small section around this value. The deviation of position as well as the rate of movement through the buffer are determined by a mantissa-exponent representation each. Finally four types of movement are defined: 0 = forward, 1 = backward, 2 = forward and backward, 3 = random with cubic interpolation.

    +

    Within the upper block there are two or three differently colored sections, separating controls of source and effects (one or two). PbindFx parameters can be directly passed to the source grain player synths (such a 'amp'), but they might also be used to process the actual synth args, e.g. 'absEnv' determines if parameters 'att' and 'rel' are to be taken literally or relative with respect to an "absolute" 'overlap' value (see pseudo method 'attRel' above), this kind of processing is defined within the PbindFx. Not all parameters need to occur in the VarGui instance, they might also be controlled by PL pattern proxies, in that case the pattern sources are defined in topEnvironment later on.

    +

    Amplitude parameters 'amp' occur with grain synths as well as with effect synths, in the latter case they appear with the fx name as suffix in the gui. Their meaning is not the same in all cases, mostly they are understood as amplitudes of the fx-processed signal ("pre-mix"), but they can be applied to the mix too ("post-mix"). In the case of a combined fx/no-fx sequencing a more fine-tuned amplitude control can be achieved with applying a separate gain fx, which is used instead of no effect. For the the sake of clarity this is only done within the last part.

    +

    The EventStreamPlayer derived from the PbindFx (e0 on the right side) and the buffer position synth can be started separately by pressing the green buttons. Note that patches can also be controlled by setting certain PL proxy pattern sources as shown at the bottom of part 1. Regarding the compositional process of kitchen studies, the final sounding result very much depends on the decision which parameters are controlled by pattern sequencing and which ones are controlled by gui-tunable parameters. Such decisions happened during a long process of experimenting which usually started with gui control for all parameters. However for the final version no live-control with sliders has been recorded, parameters were either fixed or algorithmically controlled by patterns.

    +


    +


    +


    +


    +

    Part 1 – comb delay plus separate delay modulation

    +


    +

    // This granulation combines two effects in sequence.

    +

    // The same effect chain (fxOrder = [1, 2]) is used for all grains but parameters change.

    +


    +

    (

    +

    // comb delay

    +


    +

    SynthDef(\comb, { |out = 0, in, mix = 0.5, amp = 1, maxDelayTime = 0.2, delayTime = 0.02,

    +

    decayTime = 1|

    +

    var sig, inSig = In.ar(in, 2);

    +

    sig = CombL.ar(inSig, maxDelayTime, delayTime, decayTime, amp);

    +

    OffsetOut.ar(out, (1 - mix) * inSig + (sig * mix));

    +

    }).add;

    +


    +

    // modulation of delay

    +

    // modInd is a provisional measure for delay modulation in analogy to FM's index

    +


    +

    SynthDef(\delayMod, { |out = 0, in, delayTime = 0.1, maxDelayTime = 2,

    +

    modFreq = 0, modIndM = 0, modIndE = -5, mix = 1, amp = 0.1|

    +

    var inSig = In.ar(in, 2), sig, modDev;

    +

    modDev = 10 ** modIndE * modIndM * modFreq;

    +

    sig = DelayC.ar(inSig, maxDelayTime, SinOsc.ar(modFreq, 0, modDev, delayTime), amp);

    +

    OffsetOut.ar(out, (1 - mix) * inSig + (sig * mix));

    +

    }).add;

    +


    +


    +

    // topEnvironment needed for pattern proxies

    +

    // the slider variables are set in dedicated environments by VarGui

    +


    +

    t = topEnvironment.push;

    +


    +

    // bus to DC leaker

    +

    a = Bus.audio(s, 2);

    +


    +

    // bus for position control

    +

    c = Bus.control(s, 2);

    +


    +

    // PLs with envir = t will read from topEnvironment Patterns/Streams (see below)

    +

    // other PLs will read slider values

    +


    +

    // produce three minutes audio

    +


    +

    p = Pfindur(180, PbindFx([

    +

    \instrument, \posPlay,

    +

    \sndBuf, b,

    +

    \out, a,

    +


    +

    \dur, 1 / PL(\trigRate),

    +

    \granDur, Pkey(\dur) * PL(\overlap, envir: t),

    +


    +

    \pos, c.subBus(0).asMap,

    +

    \posDev, c.subBus(1).asMap,

    +


    +

    \rate, PL(\rate, envir: t),

    +

    \amp, PL(\amp),

    +


    +

    \pan, PLseq([-1, 1]) * PL(\panMax),

    +

    // determining concrete envelope times (see Function attRel above)

    +

    [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) },

    +


    +

    \fxOrder, PL(\fxOrder, envir: t),

    +

    // comb delay time needed for lag in case of no comb

    +

    \delayTime_comb, PL(\delayTime_comb, envir: t).collect { |x| d.dt = x; x },

    +

    \lag, Pfunc { |ev|  (ev.fxOrder.asArray.includes(1)).if { 0 }{ ev.delayTime_comb } },

    +

    \cleanupDelay, 0.3

    +

    ],[

    +

    \fx, \comb,

    +

    \decayTime, PL(\decayTime_comb),

    +

    \delayTime, Pfunc { d.dt },

    +

    \mix, PL(\mix_comb),

    +

    \amp, PL(\amp_comb),

    +

    \cleanupDelay, Pkey(\decayTime)

    +

    ],[

    +

    \fx, \delayMod,

    +

    \mix, PL(\mix_delayMod),

    +

    \amp, PL(\amp_delayMod),

    +

    \modIndM, PL(\modIndM_delayMod),

    +

    \modIndE, PL(\modIndE_delayMod),

    +

    \modFreq, PL(\modFreq_delayMod, envir: t),

    +

    \cleanupDelay, 0.1

    +

        ]

    +

    ));

    +


    +

    // slider and player control

    +

    v = VarGui([

    +

    \att, [1, 200, \lin, 0, 6.97],

    +

        \rel, [1, 200, \lin, 0, 8.96],

    +

         \absEnv, [0, 1, \lin, 1, 0.0],

    +

    \trigRate, [1, 200, \lin, 0, 66.67],

    +

    \panMax, [0, 1, \lin, 0, 0.89],

    +

        \amp, [0.0, 3, \lin, 0, 1],

    +


    +

    \decayTime_comb, [0.001, 1, \lin, 0, 0.14086],

    +

        \mix_comb, [0, 1, \lin, 0, 0.7],

    +

        \amp_comb, [0, 3, \lin, 0, 1],

    +


    +

        \modIndE_delayMod, [-6, -2, \lin, 1, -5.0],

    +

        \modIndM_delayMod, [0, 10, \lin, 0, 1.5],

    +

        \mix_delayMod, [0, 1, \lin, 0, 0.88],

    +

        \amp_delayMod, [0, 3, \lin, 0, 1.0]

    +

    ],[

    +

    \sndBuf, b.bufnum,

    +

        \posLo, [0, 0.99, \lin, 0, 0.2673],

    +

       \posHi, [0, 0.99, \lin, 0, 0.3267],

    +

        \posDevE, [-6, 0, \lin, 1, -5],

    +

        \posDevM, [0.0, 10, \lin, 0, 6.7],

    +


    +

        \posRateE, [-4, 2, \lin, 1, -1],

    +

        \posRateM, [0.1, 10, \lin, 0, 0.694],

    +

      \type, [0, 3, \lin, 1, 3],

    +

    \out, c.index

    +

    ], stream: p, synth: \pos

    +

    );

    +


    +

    // gui look, color grouping

    +

    w = (

    +

    varColorGroups: (0..12).clumps([6, 3, 4]),

    +

    synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]),

    +

    tryColumnNum: 1,

    +

    labelWidth: 130,

    +

    sliderWidth: 350,

    +

    sliderHeight: 18,

    +

    playerHeight: 18

    +

    );

    +

    )

    +


    +


    +


    +

    // running the patch: evaluate this, 

    +

    // then in gui start position synth and PbindFx stream by pressing both green buttons

    +


    +

    // Psegs are very practical for defining LFO-like behaviour in SC lang

    +


    +

    (

    +

    x = Synth(\leakDC, [\out, 0, \in, a]);

    +


    +

    ~overlap = Pseg(PLwrand([0.05, 0.5, 1], [4, 1, 1].normalizeSum), Pwhite(0.5, 1), \sine);

    +

    ~rate = Pseg(Pwhite(0.05, 1), Pexprand(0.01, 0.5), \sine);

    +

    ~delayTime_comb = Pseg(PLseq([0.02, 0.002]), Pwhite(8, 15));

    +

    ~fxOrder = [1, 2];

    +

    ~modFreq_delayMod = Pseg(Pwhite(10, 150), Pwhite(2, 5), \sine);

    +


    +

    v.performWithEnvir(\gui, w)

    +

    )

    +


    +

    // while running the patch you can play with sliders and

    +

    // exchange the control patterns in top envir on the fly:

    +


    +

    ~delayTime_comb = 0.002;

    +

    ~rate = 0.5;

    +


    +

    ~modFreq_delayMod = 70;

    +

    ~modFreq_delayMod = 50;

    +


    +

    ~modFreq_delayMod = Pseg(Pwhite(10, 150), Pwhite(2, 5), \sine);

    +


    +


    +

    // experiment with fx sequencing: no - comb - (comb > delay modulation)

    +


    +

    ~fxOrder = PLseq([0, 1, [1, 2]]);

    +

    ~fxOrder = Pstutter(Pwhite(1, 10), PLseq([0, 1, [1, 2]]));

    +


    +


    +

    // after stopping free leakDC synth

    +


    +

    x.free

    +


    +


    +


    +

    Part 2 – rectangular comb (FFT)

    +


    +

    (

    +

    // rectangular comb, FFT processing per grain

    +


    +

    SynthDef(\pv_rectComb, { |out = 0, in, numTeeth = 0, width = 0.5, phase = 0, mix = 1,

    +

    amp = 0.1|

    +

        var chain, inSig = In.ar(in, 2), sig, bufSize = 512, inSigDelayed;

    +


    +

        chain = FFT({ LocalBuf(bufSize) } ! 2, inSig);

    +

        chain = PV_RectComb(chain, numTeeth, phase, width);

    +

    sig = IFFT(chain) * amp;

    +

    // for mix we have to take into account FFT delay

    +

    inSigDelayed = DelayL.ar(

    +

    inSig,

    +

    0.1,

    +

    bufSize / s.sampleRate - (s.options.blockSize / s.sampleRate)

    +

    );

    +

    OffsetOut.ar(out, mix * sig + ((1 - mix) * inSigDelayed));

    +

    }).add;

    +


    +


    +

    t = topEnvironment.push;

    +


    +

    a = Bus.audio(s, 2);

    +

    c = Bus.control(s, 2);

    +


    +

    // play two loops with three "interludes" (see Task below)

    +


    +

    p = Pfindur(178, PbindFx([

    +

    \instrument, \posPlay,

    +

    \sndBuf, b,

    +

    \out, a,

    +


    +

    \dur, 1 / PL(\trigRate),

    +

    \granDur, Pkey(\dur) * PL(\overlap),

    +


    +

    \pos, c.subBus(0).asMap,

    +

    \posDev, c.subBus(1).asMap,

    +


    +

    \rate, PL(\rate, envir: t),

    +

    \amp, PL(\amp),

    +


    +

    \pan, PLseq([-1, 1]) * PL(\panMax),

    +

    [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) },

    +


    +

    \fxOrder, PLseq(\fxOrder, envir: t),

    +

    \cleanupDelay, 0.3

    +

    ],[

    +

    \fx, \pv_rectComb,

    +

    \mix, PL(\mix_rectComb, envir: t),

    +

    \amp, PL(\amp_rectComb),

    +


    +

    \numTeeth, PL(\numTeeth_rectComb, envir: t),

    +

    \width, PL(\width_rectComb, envir: t),

    +

    \phase, PL(\phase_rectComb, envir: t),

    +


    +

    \cleanupDelay, 0.2

    +

        ]

    +

    ));

    +


    +

    // timed pattern control for interludes, done with a Task

    +


    +

    u = Task({

    +

    var times_1 = PLseq([10, 10, 20, 30]).iter;

    +

    var times_2 = PLseq([7, 8, 4, 0]).iter;

    +


    +

    loop {

    +

    var tm;

    +

    ~numTeeth_rectComb = 10;

    +

    ~width_rectComb = 0.05;

    +

    ~rate = 0.2;

    +


    +

    tm = times_1.next;

    +

    tm.wait;

    +


    +

    ~numTeeth_rectComb = Pstutter(Pwhite(5, 30), Pwhite(3, 15));

    +

    ~rate = Pstutter(Pwhite(50, 100), Pwhite(0.3, 0.5));

    +

    ~width_rectComb = Pbrown(0.2, 0.5, 0.02);

    +


    +

    tm = times_2.next;

    +

    tm.wait;

    +

    }

    +

    }.inEnvir(t));

    +


    +


    +

    v = VarGui([

    +

    // separate Environments for Task and PbindFx player

    +

    [],[

    +

        \att, [1, 200, \lin, 0, 7],

    +

        \rel, [1, 200, \lin, 0, 7],

    +

         \absEnv, [0, 1, \lin, 1, 0],

    +

    \overlap, [0.05, 15, \lin, 0, 3.3],

    +

    \trigRate, [1, 200, \lin, 0, 54.73],

    +


    +

    \panMax, [0, 1, \lin, 0, 0.99],

    +

        \amp, [0.0, 3, \lin, 0, 0.15],

    +


    +

    \amp_rectComb, [0, 10, \lin, 0, 5.6]

    +

    ]],[

    +

    \sndBuf, b.bufnum,

    +

        \posLo, [0, 0.99, \lin, 0, 0.2574],

    +

       \posHi, [0, 0.99, \lin, 0, 0.3267],

    +

        \posDevE, [-6, 0, \lin, 1, -5],

    +

        \posDevM, [0.0, 10, \lin, 0, 1.9],

    +


    +

        \posRateE, [-4, 2, \lin, 1, -1],

    +

        \posRateM, [0.1, 10, \lin, 0, 5.05],

    +

      \type, [0, 3, \lin, 1, 3],

    +

    \out, c.index

    +

    ], stream: [u, p], synth: \pos

    +

    );

    +


    +

    w = (

    +

    varColorGroups: (0..7).clumps([7, 1]),

    +

    synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]),

    +

    tryColumnNum: 1,

    +

    labelWidth: 130,

    +

    sliderWidth: 350,

    +

    sliderHeight: 18,

    +

    playerHeight: 18

    +

    );

    +

    )

    +


    +


    +

    // running the patch: evaluate this, 

    +

    // then in gui start position synth  

    +

    // start PbindFx / Task players together by pressing their green buttons with shift-click

    +


    +

    // while running the patch check modified slider values and 

    +

    // consider pattern replacements as shown in part 1

    +


    +


    +

    (

    +

    x = Synth(\leakDC, [\out, 0, \in, a]);

    +


    +

    ~mix_rectComb = 0.75;

    +

    ~phase_rectComb = Pstutter(Pwhite(1, 4), Pwhite(0.0, 0.6));

    +

    ~fxOrder = [1];

    +


    +

    v.performWithEnvir(\gui, w)

    +

    )

    +


    +


    +

    // after stopping free leakDC synth

    +


    +

    x.free

    +


    +


    +


    +

    Part 3 – resampling

    +


    +

    (

    +

    // fx with "post-mix" amplitude

    +


    +

    SynthDef(\resample, { |out = 0, in, mix = 0.5, amp = 1, resampleRate = 44100|

    +

    var sig, inSig = In.ar(in, 2);

    +

    sig = Latch.ar(inSig, Impulse.ar(resampleRate));

    +

    OffsetOut.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp);

    +

    }).add;

    +


    +

    t = topEnvironment.push;

    +


    +

    a = Bus.audio(s, 2);

    +

    c = Bus.control(s, 2);

    +


    +

    p = Pfindur(90, PbindFx([

    +

    \instrument, \posPlay,

    +

    \sndBuf, b,

    +

    \out, a,

    +


    +

    \dur, 1 / PL(\trigRate, envir: t),

    +

    \granDur, Pkey(\dur) * PL(\overlap),

    +


    +

    \pos, c.subBus(0).asMap,

    +

    \posDev, c.subBus(1).asMap,

    +


    +

    \rate, PL(\rate, envir: t),

    +

    \amp, PL(\amp),

    +


    +

    \pan, PLseq([-1, 1]) * PL(\panMax),

    +

    [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) },

    +


    +

    \fxOrder, PL(\fxOrder, envir: t),

    +

    \cleanupDelay, 0.3

    +

    ],[

    +

    \fx, \resample,

    +

    \mix, PL(\mix_resample, envir: t),

    +

    \amp, PL(\amp_resample),

    +

    \resampleRate, PL(\resampleRate_resample, envir: t),

    +

    \cleanupDelay, 0.01

    +

        ]

    +

    ));

    +


    +

    v = VarGui([

    +

    \att, [1, 200, \lin, 0, 4.98],

    +

        \rel, [1, 200, \lin, 0, 4.98],

    +

         \absEnv, [0, 1, \lin, 1, 1.0],

    +

    \overlap, [0.05, 15, \lin, 0, 3.5],

    +


    +

    \panMax, [0, 1, \lin, 0, 0.93],

    +

        \amp, [0.0, 3, \lin, 0, 0.15],

    +


    +

    \amp_resample, [0, 3, \lin, 0, 2.7]

    +

    ],[

    +

    \sndBuf, b.bufnum,

    +

        \posLo, [0, 0.99, \lin, 0, 0.27],

    +

       \posHi, [0, 0.99, \lin, 0, 0.34],

    +

        \posDevE, [-6, 0, \lin, 1, -5],

    +

        \posDevM, [0.0, 10, \lin, 0, 0.3],

    +


    +

        \posRateE, [-4, 2, \lin, 1, -1],

    +

        \posRateM, [0.1, 10, \lin, 0, 3.5],

    +

      \type, [0, 3, \lin, 1, 3],

    +

    \out, c.index

    +

    ], stream: p, synth: \pos

    +

    );

    +


    +

    w = (

    +

    varColorGroups: (0..6).clumps([6, 1]),

    +

    synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]),

    +

    tryColumnNum: 1,

    +

    labelWidth: 110,

    +

    sliderWidth: 350,

    +

    sliderHeight: 18,

    +

    playerHeight: 18

    +

    );

    +

    )

    +


    +


    +

    // running the patch: evaluate this, 

    +

    // then in gui start position synth and PbindFx stream by pressing both green buttons

    +


    +

    // while running the patch check modified slider values and 

    +

    // consider pattern replacements as shown in part 1

    +


    +

    (

    +

    Synth(\leakDC, [\out, 0, \in, a]);

    +


    +

    ~resampleRate_resample = Pn(Plazy {

    +

    var freqs = (1..rrand(8, 15)) * rrand(100, 600);

    +

    Pseq(freqs, rrand(3, 6))

    +

    });

    +


    +

    ~fxOrder = 1;

    +


    +

    ~mix_resample = Pseg(

    +

    PLseq([0.0, 0.9]),

    +

    // see PS help, examples for "counted embedding"

    +

    PLseq([

    +

    PS(Pwhite(2.0, 3), Pwhite(1, 2)),

    +

    PS(Pwhite(0.03, 0.05), Pwhite(50, 80))

    +

    ]),

    +

    \step

    +

    );

    +


    +

    // random quarter tone row

    +

    ~rate = Pseg(PLshuf((-24..24)/2).midiratio, Pwhite(0.2, 2), \step);

    +


    +

    ~trigRate = Pseg(Pwhite(40, 120), Pwhite(0.5, 2), \sine);

    +


    +

    v.performWithEnvir(\gui, w)

    +

    )

    +


    +

    // after stopping free leakDC synth

    +


    +

    x.free

    +


    +


    +

    Part 4 – spectral complements (FFT)

    +


    +

    (

    +

    // emphasizes / supresses bin range and / or complement

    +

    // uses pseudo ugens PV_BinRange and PV_BinGap

    +


    +

    // freqLo and freqHi define the range

    +

    // rangeMul is the multiplier for the selected band

    +

    // compMul is the multiplier for the rest of the spectrum

    +


    +

    SynthDef(\pv_binRangeBal, { |out = 0, in, freqLo = 80, freqHi = 300, rangeMul = 1, compMul = 1, mix = 1|

    +

    var chain, chain_range, chain_comp, inSig = In.ar(in, 2), sig, bufSize = 2048,

    +

    lo, hi, binRange, binNum, inSigDelayed;

    +


    +

    binRange = s.sampleRate / bufSize;

    +

    binNum = (freqHi - freqLo / binRange).round;

    +

    lo = (freqLo / binRange).round;

    +

    hi = (freqHi / binRange).round;

    +


    +

    chain = FFT({ LocalBuf(bufSize) } ! 2, inSig);

    +

    chain_range = PV_BinRange(chain, lo, hi);

    +

    chain_comp = PV_BinGap(chain, lo, hi);

    +


    +

    sig = IFFT(chain_range) * rangeMul + (IFFT(chain_comp) * compMul);

    +

    inSigDelayed = DelayL.ar(

    +

    inSig,

    +

    0.1,

    +

    bufSize / s.sampleRate - (s.options.blockSize / s.sampleRate)

    +

    );

    +

    OffsetOut.ar(out, mix * sig + ((1 - mix) * inSigDelayed));

    +

    }).add;

    +


    +


    +

    t = topEnvironment.push;

    +


    +

    a = Bus.audio(s, 2);

    +

    c = Bus.control(s, 2);

    +


    +

    p = Pfindur(200, PbindFx([

    +

    \instrument, \posPlay,

    +

    \sndBuf, b,

    +

    \out, a,

    +


    +

    \dur, 1 / PL(\trigRate),

    +

    \granDur, Pkey(\dur) * PL(\overlap),

    +


    +

    \pos, c.subBus(0).asMap,

    +

    \posDev, c.subBus(1).asMap,

    +


    +

    \rate, PL(\rate, envir: t),

    +

    \amp, PL(\amp),

    +


    +

    \pan, PLseq([-1, 1]) * PL(\panMax),

    +

    [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) },

    +


    +

    \fxOrder, PL(\fxOrder, envir: t),

    +

    \cleanupDelay, 0.3

    +

    ],[

    +

    \fx, \pv_binRangeBal,

    +

    \mix, PL(\mix_pv_binRangeBal),

    +


    +

    \freqLo, PL(\freqLo_pv_binRangeBal, envir: t),

    +

    \freqHi, Pkey(\freqLo) + PL(\freqRange_pv_binRangeBal, envir: t),

    +


    +

    // multipliers for spectral band and complement are given as tupel 'muls'

    +

    \muls, PL(\muls_pv_binRangeBal, envir: t),

    +

    \rangeMul, Pkey(\muls).collect(_[0]),

    +

    \compMul, Pkey(\muls).collect(_[1]),

    +


    +

    \cleanupDelay, 0.2

    +

        ]

    +

    ));

    +


    +

    v = VarGui([

    +

    \att, [1, 200, \lin, 0, 3],

    +

        \rel, [1, 200, \lin, 0, 3],

    +

         \absEnv, [0, 1, \lin, 1, 0],

    +


    +

        \overlap, [0.1, 2, \lin, 0, 1.45],

    +

    \trigRate, [1, 200, \lin, 0, 118.41],

    +


    +

    \panMax, [0, 1, \lin, 0, 0.88],

    +

        \amp, [0.0, 3, \lin, 0, 0.9],

    +


    +

    \mix_pv_binRangeBal, [0, 1, \lin, 0, 1]

    +

    ],[

    +

    \sndBuf, b.bufnum,

    +

        \posLo, [0, 0.99, \lin, 0, 0.21],

    +

       \posHi, [0, 0.99, \lin, 0, 0.34],

    +

        \posDevE, [-6, 0, \lin, 1, -5],

    +

        \posDevM, [0.0, 10, \lin, 0, 1.0],

    +


    +

        \posRateE, [-4, 2, \lin, 1, -2],

    +

        \posRateM, [0.1, 10, \lin, 0, 2.278],

    +

      \type, [0, 3, \lin, 1, 3],

    +


    +

    \out, c.index

    +

    ], stream: p, synth: \pos

    +

    );

    +


    +

    w = (

    +

    varColorGroups: (0..7).clumps([7, 1]),

    +

    synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]),

    +

    tryColumnNum: 1,

    +

    labelWidth: 130,

    +

    sliderWidth: 350,

    +

    sliderHeight: 18,

    +

    playerHeight: 18

    +

    );

    +

    )

    +


    +


    +

    // running the patch: evaluate this, 

    +

    // then in gui start position synth and PbindFx stream by pressing both green buttons

    +


    +

    // while running the patch check modified slider values and 

    +

    // consider pattern replacements as shown in part 1

    +


    +

    (

    +

    Synth(\leakDC, [\out, 0, \in, a]);

    +


    +

    ~fxOrder = 1;

    +


    +

    // double source grain in octave distance

    +

    ~rate = [0.15, 0.3];

    +


    +

    // pattern for lower bound of spectral band

    +

    ~freqLo_pv_binRangeBal = Pn(Plazy {

    +

    var x = { exprand(200, 4000)  } ! rrand(2, 4);

    +

    Pseq(x, rrand(5, 15));

    +

    });

    +


    +

    ~freqRange_pv_binRangeBal = 2500;

    +


    +

    // this is a bit more complicated

    +

    // polyrhythm for multipliers of band and complement

    +

    // it becomes more clear when applying trace to the following patterns

    +


    +

    ~zeroOneSeqTupleStream = PLshufn([

    +

    [[0, 1, 1], [0, 0, 1, 1]],

    +

    [[0, 1, 1], [0, 1, 1, 1]],

    +

    [[0, 0, 1], [0, 0, 1, 1]],

    +

    [[0, 0, 1], [0, 1, 1, 1]],

    +

    ]).iter;

    +


    +

    ~muls_pv_binRangeBal = Pn(Plazy ({

    +

    var tuple = ~zeroOneSeqTupleStream.next;

    +

    if (0.5.coin) { tuple = tuple.reverse };

    +

    if (0.5.coin) {

    +

    tuple[0] = tuple[0].reverse;

    +

    tuple[1] = tuple[1].reverse;

    +

    };

    +

    Pfinval([500, 400, 300].choose, Ptuple([

    +

    PLseq(tuple[0]),

    +

    PLseq(tuple[1])

    +

    ]))

    +

    }.inEnvir));

    +


    +

    v.performWithEnvir(\gui, w)

    +

    )

    +


    +

    // after stopping free leakDC synth

    +


    +

    x.free

    +


    +


    +

    Part 5 – frequency shift with feedback

    +


    +

    (

    +

    // frequency shift with feedback

    +

    // "post-mix" fx amplitude

    +


    +

    // fx with feedback obviously needs envelope !

    +


    +

    SynthDef(\freqShift, { |out = 0, in, mix = 1, freq = 0, fbAmp = 0,

    +

    granDur = 0.1, att = 0.01, rel = 0.01, amp = 0.1|

    +

    var inSig = In.ar(in, 2), sig, fb, env;

    +

    sig = inSig + (fbAmp * LocalIn.ar(2));

    +

    sig = Limiter.ar(sig);

    +

    sig = FreqShift.ar(sig, freq);

    +

    LocalOut.ar(sig);

    +


    +

    sig = LPF.ar(sig, 10000);

    +

    // delayed attack is functioning as additional feedback control

    +

    env = EnvGen.ar(Env([0, 0, 1, 1, 0], [0.01, att, granDur - att - rel, rel]), doneAction: 2);

    +

    OffsetOut.ar(out, (mix * sig + ((1 - mix) * inSig)) * amp * env);

    +

    }).add;

    +


    +

    t = topEnvironment.push;

    +


    +

    a = Bus.audio(s, 2);

    +

    c = Bus.control(s, 2);

    +


    +

    p = PbindFx([

    +

    \instrument, \posPlay,

    +

    \sndBuf, b,

    +

    \out, a,

    +


    +

    \dur, 1 / PL(\trigRate),

    +

    \granDur, Pkey(\dur) * PL(\overlap),

    +


    +

    \pos, c.subBus(0).asMap,

    +

    \posDev, c.subBus(1).asMap,

    +


    +

    \rate, PL(\rate, envir: t),

    +

    \amp, PL(\amp),

    +


    +

    \pan, PLseq([-1, 1]) * PL(\panMax),

    +

    [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) },

    +


    +

    // envelope data to be shared with fx

    +

    \do, Ptuple([Pkey(\granDur), Pkey(\att), Pkey(\rel)])

    +

    .collect { |x|  t[\share] =  x },

    +


    +

    \fxOrder, PL(\fxOrder, envir: t),

    +

    +

    \cleanupDelay, Pfunc { |ev|  max(0.2, ev[\granDur] - ev[\dur]) }

    +

    ],[

    +

    \fx, \freqShift,

    +

    \mix, PL(\mix_freqShift),

    +

    \amp, PL(\amp_freqShift),

    +

    [\granDur, \att, \rel], Pfunc { t[\share] },

    +

    \granDur, Pkey(\granDur) * 0.9,

    +

    \freq, PL(\freq_freqShift, envir: t),

    +

    \fbAmp, PL(\fbAmp_freqShift, envir: t),

    +


    +

    \cleanupDelay, 0.5

    +

        ]

    +

    );

    +


    +


    +

    v = VarGui([

    +

    \att, [1, 200, \lin, 0, 3],

    +

        \rel, [1, 200, \lin, 0, 7],

    +

         \absEnv, [0, 1, \lin, 1, 1.0],

    +


    +

        \overlap, [0.05, 15, \lin, 0, 6.927],

    +

    \trigRate, [1, 200, \lin, 0, 24.88],

    +


    +

    \panMax, [0, 1, \lin, 0, 0.84],

    +

        \amp, [0.0, 1, \lin, 0, 0.06],

    +


    +

        \mix_freqShift, [0, 1, \lin, 0, 0.54],

    +

        \amp_freqShift, [0.1, 2, \lin, 0, 0.3]

    +

    ],[

    +

    \sndBuf, b.bufnum,

    +

        \posLo, [0, 0.99, \lin, 0, 0.21],

    +

       \posHi, [0, 0.99, \lin, 0, 0.34],

    +

        \posDevE, [-6, 0, \lin, 1, -5],

    +

        \posDevM, [0.0, 10, \lin, 0, 0.5],

    +


    +

        \posRateE, [-4, 2, \lin, 1, 0],

    +

        \posRateM, [0.1, 10, \lin, 0, 1.486],

    +

      \type, [0, 3, \lin, 1, 3],

    +


    +

    \out, c.index

    +

    ], stream: p, synth: \pos

    +

    );

    +


    +


    +

    w = (

    +

    varColorGroups: (0..8).clumps([7, 2]),

    +

    synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]),

    +

    tryColumnNum: 1,

    +

    labelWidth: 130,

    +

    sliderWidth: 350,

    +

    sliderHeight: 18,

    +

    playerHeight: 18

    +

    );

    +

    )

    +


    +


    +

    // running the patch: evaluate this, 

    +

    // then in gui start position synth and PbindFx stream by pressing both green buttons

    +


    +

    // while running the patch check modified slider values and 

    +

    // consider pattern replacements as shown in part 1

    +


    +

    (

    +

    Synth(\leakDC, [\out, 0, \in, a]);

    +


    +

    ~freq_freqShift = Pstutter(Pwhite(10, 50), Pwhite(-200, 50, 1));

    +

    ~fbAmp_freqShift = Pstutter(Pstutter(Pwhite(2, 5), Pwhite(1, 2)), PLseq([1, -2]));

    +

    ~fxOrder = [1];

    +


    +

    ~rate = Pn(Plazy {

    +

    Pseries(exprand(0.3, 0.7), rrand(0.02, 0.1), rrand(5, 20));

    +

    }) * 0.8;  

    +


    +

    v.performWithEnvir(\gui, w)

    +

    )

    +


    +

    // after stopping free leakDC synth

    +


    +

    x.free

    +


    +


    +

    Part 6 – band pass

    +


    +

    (

    +

    // band pass

    +

    // "post-mix" fx amplitude

    +


    +

    SynthDef(\bpf, { |out = 0, in, freq = 440, rq = 0.1, amp = 1, mix = 1|

    +

    var sig, inSig = In.ar(in, 2);

    +

    sig = BPF.ar(inSig, freq, rq);

    +

    OffsetOut.ar(out, (mix * sig + ((1 - mix) * inSig)) * amp);

    +

    }).add;

    +


    +

    // gain as fx for better control of balancing when sequencing grains with and without band pass

    +


    +

    SynthDef(\gain, { |out = 0, in, amp = 1|

    +

    var inSig = In.ar(in, 2);

    +

    OffsetOut.ar(out, inSig * amp);

    +

    }).add;

    +


    +


    +

    t = topEnvironment.push;

    +


    +

    a = Bus.audio(s, 2);

    +

    c = Bus.control(s, 2);

    +


    +

    // duration defined by 'rate' with Pfinval

    +

    p = PbindFx([

    +

    \instrument, \posPlay,

    +

    \sndBuf, b,

    +

    \out, a,

    +


    +

    \dur, 1 / PL(\trigRate),

    +

    \granDur, Pkey(\dur) * PL(\overlap),

    +


    +

    \pos, c.subBus(0).asMap,

    +

    \posDev, c.subBus(1).asMap,

    +


    +

    \rate, PL(\rate, 1, envir: t),

    +

    \amp, PL(\amp),

    +


    +

    \pan, PLseq([-1, 1]) * PL(\panMax),

    +

    [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) },

    +


    +

    \fxOrder, PL(\fxOrder, envir: t),

    +

    \cleanupDelay, 0.3

    +

    ],[

    +

    \fx, \gain,

    +

    \amp, PL(\amp_gain),

    +


    +

    \cleanupDelay, 0.01

    +

    ],[

    +

    \fx, \bpf,

    +

    \freq, PL(\freq_bpf, envir: t),

    +

    \rq, PL(\rq_bpf),

    +

    \mix, PL(\mix_bpf),

    +

    \amp, PL(\amp_bpf),

    +


    +

    \cleanupDelay, 0.01

    +

    ]

    +

    );

    +


    +

    v = VarGui([

    +

        \att, [1, 200, \lin, 0, 4.98],

    +

        \rel, [1, 200, \lin, 0, 4.98],

    +

         \absEnv, [0, 1, \lin, 1, 1.0],

    +

         \overlap, [0.05, 15, \lin, 0, 6.7775],

    +


    +

    \trigRate, [1, 200, \lin, 0, 176.12],

    +

    \panMax, [0, 1, \lin, 0, 0.83],

    +

        \amp, [0.0, 3, \lin, 0, 0.75],

    +


    +

        \amp_gain, [0.0, 3, \lin, 0, 0.36],

    +


    +

        \rq_bpf, [0.01, 1, \lin, 0, 0.0397],

    +

        \mix_bpf, [0, 1, \lin, 0, 0.91],

    +

        \amp_bpf, [0, 1, \lin, 0, 2.7],

    +

    ],[

    +

    \sndBuf, b.bufnum,

    +

        \posLo, [0, 0.99, \lin, 0, 0.2574],

    +

       \posHi, [0, 0.99, \lin, 0, 0.4059],

    +

        \posDevE, [-6, 0, \lin, 1, -4],

    +

        \posDevM, [0.0, 10, \lin, 0, 1.0],

    +


    +

        \posRateE, [-4, 2, \lin, 1, -1],

    +

        \posRateM, [0.1, 10, \lin, 0, 0.892],

    +

      \type, [0, 3, \lin, 1, 3],

    +

    \out, c.index

    +

    ], stream: p, synth: \pos

    +

    );

    +


    +

    w = (

    +

    varColorGroups: (0..10).clumps([8, 3]),

    +

    synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]),

    +

    tryColumnNum: 1,

    +

    labelWidth: 130,

    +

    sliderWidth: 350,

    +

    sliderHeight: 18,

    +

    playerHeight: 18

    +

    );

    +

    )

    +


    +


    +

    // running the patch: evaluate this, 

    +

    // then in gui start position synth and PbindFx stream by pressing both green buttons

    +


    +

    // while running the patch check modified slider values and 

    +

    // consider pattern replacements as shown in part 1

    +


    +

    (

    +

    Synth(\leakDC, [\out, 0, \in, a]);

    +


    +

    // "octave arpeggio" bandpass frequencies, interleaved (PS with repeats = 1)

    +

    // check other relations, repetition numbers and fxOrder sequences

    +


    +

    ~freq_bpf = PLseq([

    +

    PS(Pstutter(3, Pseg(Pwhite(200, 7000), Pwhite(0.5, 2))) * PLseq([0.5, 1, 2]), 1),

    +

    PS(Pstutter(2, Pseg(Pwhite(200, 7000), Pwhite(0.5, 2))) * PLseq([0.5, 1, 2]), 1)

    +

    ]);

    +


    +

    // start with 1 ensures that we don't have filter only in single channel

    +

    ~fxOrder = PLseq([1, 2, 2, 1]);

    +


    +

    // development by ascending rate "chords"

    +


    +

    ~rate = Pseq([

    +

    Pfinval(5582,

    +

    Pstutter(

    +

    PLseq([120, 80, 80]),

    +

    Pexprand(0.3, 1.5).clump(PLshufn((1..3)) * 2 + 1)

    +

    ).flatten

    +

    ),

    +

    Pfinval(5582,

    +

    Pstutter(

    +

    PLseq([120, 80, 80]),

    +

    Pexprand(0.3, 0.6).clump(PLshufn((1..3)) * 2 + 1)

    +

    ).flatten

    +

    ),

    +

    Pfinval(15000,

    +

    Pstutter(

    +

    PLseq([120, 80, 80]),

    +

    Pexprand(0.1, 0.2).clump(PLshufn((1..3)) * 2 + 1)

    +

    ).flatten

    +

    )

    +

    ]);

    +


    +

    v.performWithEnvir(\gui, w)

    +

    )

    +


    +

    // after stopping free leakDC synth

    +


    +

    x.free

    +


    +


    +


    +


    + + diff --git a/Help/miSCellaneous.html b/Help/miSCellaneous.html new file mode 100644 index 0000000..8e2266b --- /dev/null +++ b/Help/miSCellaneous.html @@ -0,0 +1,471 @@ + + + + + + + + + + + +

    miSCellaneous a library of SuperCollider extensions (c) 2009-2020 Daniel Mayer 

    +


    +


    +

    Version 0.23 contains these class and help files (SCDoc and old HTML system):

    +


    +


    +

    1.) Guide Introduction to miSCellaneous: recommended starting point.

    +


    +

    2.) VarGui:  a slider / player gui to set envir variables and synth controllers and play synths, 

    +

    event patterns and tasks, see also VarGui shortcut builds.

    +

    HS with VarGui, a specific tutorial about the combination of HS family and VarGui.

    +


    +

    3.) General tutorials: Event patterns and LFOs contains an overview of

    +

    related LFO-control setups with event patterns. Event patterns and Functions 

    +

    is treating requirements of the control of EventStreamPlayers with VarGui.

    +

    Event patterns and array args focusses on passing arrays to synths with patterns.

    +

    enum is a general enumeration method suited for many combinatorial problems such as 

    +

    listing subsets, partitions of integers, searching for paths within graphs etc.

    +


    +

    4.) PLx suite, dynamic scope variants of common Pattern classes for convenient replacement. 

    +

    Can be used for shorter writing of Pbinds to be played with VarGui and / or live coding, 

    +

    see PLx and live coding with Strings. PLbindef and PLbindefPar as subclasses of Pdef 

    +

    allow replacement of key streams in shortcut pseudomethod syntax.

    +

    +

    5.) PSx stream patterns, Pattern variants that have a state and can remember their last values. 

    +

    Can be used for recording streams and event streams (PS),

    +

    data sharing between event streams (PSdup), comfortable defining of subpatterns

    +

    with counted embedding, defining of recursive (event) sequences (PSrecur) and building

    +

    loops on given Patterns/Streams with a variety of options, also for live interaction (PSloop).

    +


    +

    6.) Event pattern classes for use with effects: PbindFx can handle arbitrary effect graphs per event, 

    +

    PmonoPar and PpolyPar follow the Pmono paradigm. The tutorial kitchen studies contains 

    +

    the documented source code of a fixed media piece using PbindFx for granulation.

    +

    +

    7.) Further Pattern classes: PlaceAll, Pshufn, PsymNilSafe.

    +

    PSPdiv is a dynamic multi-layer pulse divider based on Pspawner.

    +


    +

    8.) Buffer Granulation, a tutorial covering different approaches of implementing

    +

    this synthesis method in SC (server versus language control, mixed forms),

    +

    examples with VarGui, language-driven control with PLx suite patterns.

    +

    The tutorial Live Granulation summarizes direct options without explicit use of a buffer.

    +

    +

    9.) A family of classes for the use of synth values in Pbind-like objects.

    +

    Take Working with HS and HSpar as a starting point, see also

    +

    HS, PHS, PHSuse, HSpar, PHSpar, PHSparUse, PHSplayer, PHSparPlayer, PHSusePlayer.

    +

    +

    10.) EventShortcuts, a class for user-defined keywords for events and event patterns.

    +

    The tutorial Other event and pattern shortcuts collects some further abbreviations,

    +

    e.g. functional reference within events and event patterns, similar to Pkey.

    +

    +

    11.) An implementation of Xenakis' Sieves as class and pattern family, see

    +

    Sieves and Psieve patterns for an overview and examples.

    +

    +

    12.) FFT pseudo ugens for defining ranges by bin index: PV_BinRange and PV_BinGap.

    +

    +

    13.) Smooth Clipping and Folding, a suite of pseudo ugens.

    +


    +

    14.) DX suite, pseudo ugens for crossfaded mixing and fanning according to demand-rate control.

    +

    +

    15.) Idev suite, patterns and drate ugen searching for numbers with integer distance from a 

    +

    source pattern / signal.

    +

    +

    16.) Nonlinear dynamics: Fb1 for single sample feedback / feedforward and GFIS for 

    +

    generalized functional iteration synthesis. Fb1_ODE for ordinary differential equation integration.

    +

    +

    17.) ZeroXBufWr, ZeroXBufRd, TZeroXBufRd: pseudo ugens for analysis of zero crossings and 

    +

    playing sequences of segments between them with demand rate control.

    +

    +


    +

    Many of the examples here are using patterns, resp. event patterns but do not cover their basic concepts. 

    +

    For a detailled description of SC's sequencing capabilities see James Harkins' Practical Guide to Patterns 

    +

    (PG_01_Introduction), the tutorial Streams-Patterns-Events (1-7) and the Pattern help files 

    +

    (Pattern, Pbind and the type-specific ones).

    +


    +

    VarGui handles namespace separation by using different Environments.

    +

    So a gui for control of parametrized families of different types of objects can be built on the fly

    +

    (e.g. a number of EventStreamPlayers from a single Pbind definition with snippets of functional code,

    +

    a number of Function plots from a single parametric function definition etc.).

    +

    See Environment and Event helpfiles for the underlying concepts and Event patterns and Functions and 

    +

    PLx suite for their application to event patterns resp. EventStreamPlayers.

    +


    +


    +

    Requirements

    +


    +

    At least SuperCollider version 3.6 but newer versions are recommended, 

    +

    with 3.6 you'd have to use Qt GUI kit, which is the only option anyway from 3.7 onwards. 

    +

    Unable to test on 3.5 anymore, code might work, anyway old help is still supported.

    +


    +

    If you still use Cocoa or SwingOSC with these old SC versions,

    +

    you can take miSCellaneous 0.15b and add classes and help files from a 

    +

    newer version of miSCellaneous.

    +


    +

    For using VarGui with EZSmoothSlider and EZRoundSlider you would need to 

    +

    install Wouter Snoei's wslib Quark, one buffer granulation

    +

    example using Wavesets depends on Alberto de Campo's Wavesets Quark. 

    +


    +

    I tested examples on SC versions 3.6 - 3.11, 

    +

    on OS 10.8 - 10.13, Ubuntu 12.04 and Windows 7, 10; 

    +

    though not every platform / OS version / SC version combination.

    +


    +


    +

    SCDoc issues (SC 3.10)

    +


    +

    With SC 3.10.0 - SC 3.10.2 there are issues with evaluating code in the 

    +

    help file examples (double evaluation).

    +

    For these versions you'd rather copy the help file code into scd files and run it there. 

    +

    Double evaluation has been fixed with 3.10.3 (August 2019).

    +

    With SC updates to 3.10 it might happen that help file examples are invisible.

    +

    In that case delete the Help folder which resides in one of these places, depending

    +

    where you have installed:

    +


    +

    Platform.userAppSupportDir;

    +

    Platform.systemAppSupportDir;

    +


    +

    Then restart SC.

    +


    +


    +

    Installation

    +


    +

    By version 0.17 you can install either via the quarks extension management system or a 

    +

    downloaded zip from GitHub or my website. 

    +

    Both methods shouldn't be combined, e.g. if you have already done a manual install 

    +

    before by placing a miSCellaneous folder in the Extensions folder, then remove 

    +

    it from there before the quarks install.

    +


    +

    1.) Installation via Quarks

    +


    +

    This requires a SC version >= 3.7, see the recommended ways to install here:

    +


    +

    http://doc.sccode.org/Guides/UsingQuarks.html

    +

    https://github.com/supercollider-quarks/quarks

    +


    +

    After a install of a newer version of miSCellaneous do a SCDoc update by

    +


    +

    SCDoc.indexAllDocuments(true);

    +


    +


    +

    2.) Manual installation from a downloaded zip

    +


    +

    You can download the newest version from 

    +


    +

    https://github.com/dkmayer/miSCellaneous_lib

    +


    +

    and the newest and all previous versions from here:

    +


    +

    http://daniel-mayer.at

    +


    +


    +

    Copy the miSCellaneous folder into the Extensions folder and recompile 

    +

    the class library or (re-)start SC. If the Extensions folder doesn't exist you'd probably 

    +

    have to create it yourself. Check SC help for platform-specific conventions 

    +

    (or changes) of extension places.

    +


    +

    Typical user-specific extension directories:

    +


    +

    OSX: ~/Library/Application Support/SuperCollider/Extensions/

    +

    Linux: ~/.local/share/SuperCollider/Extensions/

    +


    +

    Typical system-wide extension directories:

    +


    +

    OSX: /Library/Application Support/SuperCollider/Extensions/

    +

    Linux: /usr/share/SuperCollider/Extensions/

    +


    +

    You can check Extension directories with

    +


    +

    Platform.userExtensionDir;

    +

    Platform.systemExtensionDir;

    +


    +

    On Windows see the README file of SC for the recommended extensions path.

    +

    On Windows and OSX you might have to make the concerned folders visible,

    +

    if they aren't already. The miSCellaneous folder should be placed directly

    +

    into the Extensions folder, not into a subfolder. 

    +


    +

    After a install of a newer version of miSCellaneous do a SCDoc update by

    +


    +

    SCDoc.indexAllDocuments(true);

    +


    +

    License

    +


    +

    miSCellaneous is distributed under the GNU Public License in accordance with SuperCollider.

    +

    You should have received a copy of the GNU General Public License along

    +

    with this program; if not, write to the Free Software Foundation, Inc.,

    +

    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

    +


    +


    +

    Contact

    +


    +

    Email: daniel-mayer@email.de

    +

    URL:  http://daniel-mayer.at

    +


    +


    +

    Credits

    +


    +

    Many thanks to James McCartney for developing SuperCollider, 

    +

    Alberto de Campo for showing me its capabilities,

    +

    Wouter Snoei for his nice slider classes in wslib, 

    +

    Nathaniel Virgo for his suggestions for feedback, 

    +

    David Pirrò for his hints concerning ODE integration,

    +

    James Harkins for his remarks on many things and 

    +

    the whole community for contributions and hints !

    +


    +


    +

    History

    +


    +

    v0.23 2020-04-19

    +


    +

    .) ZeroXBufWr, ZeroXBufRd, TZeroXBufRd: playing half wavesets with demand rate control

    +

    .) Remove doubled method lincurve_3_9, which caused a warning without harm

    +

    .) AddEventTypes_PbindFx: use store instead of writeDefFile in private methods

    +

    .) Minor fixes in help files

    +

    +


    +

    v0.22 2019-08-14

    +


    +

    .) Fb1_ODE and related: ordinary differential equation integration

    +

    .) Fb1: now also runs at control rate, Fb1.new is equivalent to Fb1.ar

    +

    .) Fb1: minor change of forced graph ordering

    +

    .) PbindFx: accept instruments/fxs given as Strings in pbindData key/value pairs

    +

    .) Minor fixes in help files

    +

    +


    +

    v0.21 2018-07-25

    +


    +

    .) Fb1: single sample feedback / feedforward

    +

    .) GFIS: generalized functional iteration synthesis

    +

    .) Redefined variables in Sieve, PSrecur and PSPdiv to enable inlining

    +

    .) Minor fixes in help files

    +

    +


    +

    v0.20 2018-05-21

    +


    +

    .) Idev suite, search for numbers with integer distance from a source

    +

    .) Bug fix in Integer method lcmByFactors

    +

    .) Minor fixes in help files

    +

    +


    +

    v0.19 2017-11-22

    +


    +

    .) DX, a suite of pseudo ugens for crossfaded mixing and fanning 

    +

    .) Minor adaption of PbindFx event type

    +

    .) Minor fixes in help files

    +

    +


    +

    v0.18 2017-09-26

    +


    +

    .) PLbindef / PLbindefPar: new features and implementation

    +

    .) Minor fixes in PV_BinGap and PV_BinRange

    +

    .) Minor fixes in help files

    +


    +


    +

    v0.17 2017-08-21

    +


    +

    .) Smooth Clipping and Folding, a suite of pseudo ugens

    +

    .) Added MIDI learning feature for VarGui slider control

    +

    .) Platform.miSCellaneousDirs, search for miSCellaneous folder

    +

    .) Adapted PV_BinRange and PV_BinGap to do multichannel expansion

    +

    .) Exchanged graphic examples in VarGui help (Qt now)

    +

    .) Minor fixes in help files

    +

    .) First version released via GitHub and as Quark

    +


    +


    +

    v0.16 2017-03-03

    +


    +

    .) Added PSPdiv, a dynamic multi-layer pulse divider based on Pspawner

    +

    .) Added tutorial: Live Granulation

    +

    .) Dropped miSCellaneous' b-branch: Cocoa and SwingOSC no longer supported

    +

    .) Replaced OSCpathResponder by OSCFunc in classes VarGuiPlayerSection, 

    +

      HelpSynth and HelpSynthPar

    +

    .) Minor fixes in help files

    +


    +


    +

    v0.15 2017-01-04

    +


    +

    .) Guide "Introduction to miSCellaneous"

    +

    .) kitchen studies: source code of the corresponding fixed media piece

    +

    .) PV_BinRange, PV_BinGap: FFT pseudo ugens for defining bin ranges

    +

    .) PbindFx help: new example 4a for defining implicit fx parallelism 

    +

    .) Minor fixes (help files, typos)

    +

    .) Complemeting history information (tutorials)

    +


    +


    +

    v0.14 2016-08-25

    +


    +

    .) Sieves and Psieve patterns, an implementation of Xenakis' sieves

    +

    .) PLbindef / PLbindefPar: replacement of key streams in pseudomethod syntax

    +

    .) Tutorial: PLx and live coding with Strings

    +

    .) PsymNilSafe, method symplay: avoid hangs with nil input

    +

    .) EventShortcuts: reworking of replacement, new method eventShortcuts

    +

    .) PbindFx: reworking of bus match check

    +

    .) Minor fixes (help files, typos)

    +


    +


    +

    v0.13 2015-10-28

    +


    +

    .) PbindFx: Event pattern class for effect handling on per-event base

    +

    .) Minor fixes (help files, typos)

    +


    +


    +

    v0.12 2015-05-03

    +


    +

    .) PmonoPar, PpolyPar: 

    +

      Event pattern classes for parallel setting streams and effect handling

    +

    .) PSloop: Pattern to derive loops from a given Pattern

    +

    .) Reworked replacing options of PL list patterns: cutItems arg

    +

    .) PLn: PLx Pattern for replacing with protecting periods

    +

    .) Added PLxrand, PLx version of Pxrand 

    +

    .) Changed implementations of PStream (PS) and PSrecur, 

    +

      now the MemoRoutine isn't instantiated before embedding,

    +

      this enables use of PSx patterns with VarGui

    +

    .) Fixed a bug in PL list patterns (PL_PproxyNth) that caused too early

    +

      replacements in certain cases

    +

    .) Added method bufSeq for PStream

    +

    .) Added missing help file of PLtuple

    +

    .) Minor fixes (help files, typos)

    +


    +


    +

    v0.11 2015-02-02

    +


    +

    .) Tutorial: Event patterns and array args

    +

    +


    +

    v0.10 2014-10-06

    +


    +

    .) Split into branches 0.10a (3.7 onwards) and 0.10b (from 3.4 up to 3.6.x),

    +

      with SC 3.7 SwingOSC and Cocoa aren't supported anymore

    +

    .) Class EventShortcuts and tutorial "Other event and pattern shortcuts"

    +


    +


    +

    v0.9 2014-02-18

    +


    +

    .) PSx stream patterns (classes and tutorial), based on class MemoRoutine

    +

    .) Buffer Granulation Tutorial: new examples (1c - 1e, 3d)

    +

    .) VarGui save dialog fix (was broken with 3.6)

    +

    .) Minor fixes (help files, typos)

    +


    +


    +

    v0.8 2013-05-05

    +


    +

        .) Enumeration tutorial: method enum

    +


    +


    +

    v0.7.1 2013-04-28

    +


    +

        .) Fix in PLseries and PLgeom

    +


    +


    +

    v0.7 2012-08-31

    +


    +

    .) Buffer Granulation tutorial file

    +

    .) VarGui

    +

    .) Support of wslib slider classes EZSmoothSlider and EZRoundSlider

    +

    .) Color grouping options for synth and envir variable control

    +

    .) Adapting EZSlider to ControlSpec step size (fixes certain rounding and jitter issues)

    +

    .) Multiple slider handling with modifier keys: fixes and cleanup

    +


    +


    +

    v0.6 2012-05-19

    +


    +

    .) PLx dynamic scope pattern suite

    +

    .) Implementation of a number of common Patterns as PLx classes

    +

    .) Tutorial PLx suite

    +

    .) Changing examples in some previous help files accordingly

    +

    .) Pstream, PlaceAll, Pshufn

    +


    +


    +

    v0.5 2012-03-18

    +


    +

    .) VarGui shortcut build methods

    +

    .) Use of SynthDef metadata and global ControlSpecs

    +

    .) Tutorial VarGui shortcut builds

    +

    .) Automatic Pbind generation

    +

    .) Minor fixes in VarGui init procedure

    +


    +


    +

    v0.4 2011-12-27

    +


    +

    .) VarGui support for HS family classes

    +

    .) Tutorial HS with VarGui

    +

    .) VarGui takes addAction as slider hook

    +

    .) Linux check (tested on Ubuntu):

    +

    .) Fixed system time issue in HS family

    +

    .) Specified VarGui appearance default parameters for platform and gui kit

    +

    .) Supports SCDoc, the new SC help system

    +

    .) Tutorial Event Patterns and Functions

    +

    .) Tutorial Event patterns and LFOs

    +

    .) Play methods of PHSx and PHSxPlayer now also take numbers as quant arg

    +

    .) Minor fixes in HS family

    +


    +


    +

    v0.4_beta 2011-08-18

    +


    +

    .) VarGui relaunch:

    +

    .) Player section for Synths, EventStreamPlayers and Tasks 

    +

    .) Different player modes

    +

    .) Button colors and background colors reflecting playing states 

    +

    .) Handling groups of players and sliders with modifier keys

    +

    .) Player action by mouse down or up

    +

    .) Variables can be set in different environments

    +

    .) Latency setting, global and for synth player message bundling

    +

    .) GUI appearance customization in size, arrangement and color

    +

    .) Many other changes, e.g. arg conventions 

    +

    .) Private extension methods get prefix miSC_

    +


    +


    +

    v0.3 2010-10-21

    +


    +

    .) VarGui:

    +

    .) Arrayed synth control supported

    +

    .) Slider update methods added

    +

    .) Save dialog now uses unified gui class Dialog

    +

    .) Again compiling with SC 3.3 and 3.3.1

    +

    +


    +

    v0.2 2010-09-18

    +


    +

    .) Minor adaptions to SC 3.4

    +

    .) Fixed time shifting issue

    +


    +


    +

    v0.1 2009-11-24

    +


    +

    .) VarGui, interface for envir variable and synth arg control

    +

    .) HS / HSpar etc.: classes for the use of synth values in Pbind-like objects

    +

    .) Tutorial Working with HS and HSpar

    +


    +


    + + diff --git a/HelpSource/Classes/Boolean.ext.schelp b/HelpSource/Classes/Boolean.ext.schelp new file mode 100644 index 0000000..75b9a9b --- /dev/null +++ b/HelpSource/Classes/Boolean.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_dispatchCollect + + diff --git a/HelpSource/Classes/Buffer.ext.schelp b/HelpSource/Classes/Buffer.ext.schelp new file mode 100755 index 0000000..f1b5eb4 --- /dev/null +++ b/HelpSource/Classes/Buffer.ext.schelp @@ -0,0 +1,16 @@ + +INSTANCEMETHODS:: + + +method:: adjustZeroXs +Sets all zero crossing positions of the receiver (the sound Buffer) to 0. In most cases this ensures smoother waveforms when using ZeroXBufRd / TZeroXBufRd. See link::Classes/ZeroXBufRd#Éx. 7:: and link::Classes/ZeroXBufWr#Éx. 2::, it works in analogy to ZeroXBufWr's flag adjustZeroXs set to 1. Asynchronous. + +argument::zeroXBuf +Buffer of zero crossings, assumed to be analysed with ZeroXBufWr. + +argument::action +Action function to be performed after the setting messages have been sent. Gets array of zero crossings as argument. + + + + diff --git a/HelpSource/Classes/Collection.ext.schelp b/HelpSource/Classes/Collection.ext.schelp new file mode 100644 index 0000000..5e91668 --- /dev/null +++ b/HelpSource/Classes/Collection.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_enumerateIndices, miSC_isGrouping, miSC_collectCopy, miSC_asSet + + diff --git a/HelpSource/Classes/Color.ext.schelp b/HelpSource/Classes/Color.ext.schelp new file mode 100644 index 0000000..7f69fba --- /dev/null +++ b/HelpSource/Classes/Color.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_exp, miSC_iplToGrey, miSC_dim + + diff --git a/HelpSource/Classes/ControlSpec.ext.schelp b/HelpSource/Classes/ControlSpec.ext.schelp new file mode 100644 index 0000000..d7f3efa --- /dev/null +++ b/HelpSource/Classes/ControlSpec.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_specAsArray + + diff --git a/HelpSource/Classes/DIdev.schelp b/HelpSource/Classes/DIdev.schelp new file mode 100755 index 0000000..41c48a9 --- /dev/null +++ b/HelpSource/Classes/DIdev.schelp @@ -0,0 +1,457 @@ +CLASS:: DIdev +summary:: pseudo drate ugen, searches for numbers with integer distance from a source signal, optionally avoiding repetitions within a span +categories:: Libraries>miSCellaneous>Idev suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/Idev_suite, Classes/PIdev, Classes/PLIdev + + +DESCRIPTION:: + + +DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples. + + +note:: +DIdev needs at least a SC version >= 3.7.0 for proper working. +:: + +note:: +It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples. +:: + +note:: +In contrast to PIdev and PLIdev, DIdev needs to know maximum deviations (strong::minLoDev::, strong::maxHiDev::) beforehand. Together with strong::maxLookBack:: they determine multichannel sizes, so a relatively high number of ugens might be involved. +:: + + + +CLASSMETHODS:: + + +method::new + +Creates a new DIdev object. + + +argument::in +The source signal, integer distances are calculated from the value of this signal with each trigger. Can be demand rate or other ugen. + +argument::maxLookBack +Integer, the maximum lookback span. Fixed, defaults to 3. + +argument::minLoDev +Integer, the minimum low deviation (must not be exceeded by any strong::loDev:: value). Should be negative, cannot be modulated, defaults to -3. + +argument::maxHiDev +Integer, the maximum high deviation (must not be exceeded by any strong::hiDev:: value). Should be positive, cannot be modulated, defaults to 3. + +argument::lookBack +Determines the current lookback span for avoiding repetitions. Can be modulated (demand rate or other ugen, no ar) but must not exceed strong::maxLookBack::. If no value is passed, then strong::maxLookBack:: is taken. + +argument::loDev +Determines the current low deviation for the search. Can be modulated (demand rate or other ugen) but must not exceed strong::minLoDev::. If not specified, them strong::minLoDev:: is taken. + +argument::hiDev +Determines the current high deviation for the search. Can be modulated (demand rate or other ugen) but must not exceed strong::maxHiDev::. If not specified, then strong::maxHiDev:: is taken. + +argument::thr +Threshold for equality comparison. Can be modulated (demand rate or other ugen). Defaults to 1e-3. + +argument::length +Number of repeats. Defaults to inf. + + + +section::Examples + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + + +anchor::Ex.1:: +subsection::Ex. 1: Basic usage: random choice within region without repetitions + +code:: +// constant source (72), max deviation +/- 3 +// no repetition within 5 pitches + +( +x = { + var trig = Impulse.ar(5); + var midi = Demand.ar(trig, 0, DIdev(72, 2, -1, 2)); + midi.poll(5, label: \midi); + SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1 +}.play; +) + +x.release +:: + + + + +anchor::Ex.2:: +subsection::Ex. 2: Variable deviations and lookBack + +code:: +( +x = { + |loDev = -6, hiDev = 5, lookBack = 2| + var trig = Impulse.ar(5); + // define maxLookBack, minLoDev and maxHiDev + var midi = Demand.ar(trig, 0, DIdev(72, 11, -6, 5, lookBack, loDev, hiDev)); + midi.poll(5, label: \midi); + SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1 +}.play; +) + + +// as lookBack equals 2, this defines a fixed sequence (up or down anyway) + +( +x.set(\loDev, -1); +x.set(\hiDev, 1) +) + + +// widen range + +( +x.set(\loDev, -6); +x.set(\hiDev, 5); +) + + +// force a twelve-tone row + +x.set(\lookBack, 11) + + +// contradictory input, lookBack 11 not possible within range, causes repetitions + +( +x.set(\loDev, -3); +x.set(\hiDev, 2) +) + +x.release +:: + + + + +anchor::Ex.3:: +subsection::Ex. 3: Moving source signal + +code:: +( +x = { + |loDev = -1, hiDev = 1, lookBack = 2| + var trig = Impulse.ar(7); + // define maxLookBack, minLoDev and maxHiDev + // source is rounded to integers here + var midi = Demand.ar(trig, 0, DIdev(SinOsc.ar(0.2, 0, 15, 82).round, 11, -6, 5, lookBack, loDev, hiDev)); + midi.poll(7, label: \midi); + SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1 +}.play; +) + + +// widen range and increase lookBack + +( +x.set(\loDev, -6); +x.set(\hiDev, 5); +x.set(\lookBack, 10); +) + +x.release +:: + + + +anchor::Ex.4:: +subsection::Ex. 4: Dynamic deviation range and lookBack + +code:: +// lookBack and deviations coupled here +// maxLookBack, minLoDev and maxHiDev must be large enough + +( +x = { + var trig = Impulse.ar(7); + var dev = SinOsc.ar(0.1, -pi/2).range(1, 5); + var midi = Demand.ar(trig, 0, + DIdev(78, 10, -5, 5, + SinOsc.kr(0.1, -pi/2).range(1, 5).round.poll(label: \lookBack), + dev.neg.poll(label: \loDev), + dev.poll(label: \hiDev) + ) + ); + SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) ! 2 +}.play; +) + +x.release + + +// loDev and hiDev can be demand rate + +( +x = { + var trig = Impulse.ar(5); + var hiDev = Dseq([1, 10], inf); + var midi = Demand.ar(trig, 0, + DIdev(78, 10, -10, 10, + 1, + Dseq([-10, 5], inf), + Dseq([-5, 10], inf) + ) + ); + SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) ! 2 +}.play; +) + +x.release + + +// lookBack can also be demand rate + +( +x = { + var trig = Impulse.ar(5); + var hiDev = Dseq([1, 10], inf); + var midi = Demand.ar(trig, 0, + DIdev(70, 10, -15, 15, + Dstutter(4, Dseq([1, 3], inf)), + Dstutter(4, Dseq([-9, 7], inf)), + Dstutter(4, Dseq([-8, 10], inf)) + ) + ); + midi.poll(trig); + SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) ! 2 * EnvGen.ar(Env.asr(0.15)) +}.play; +) + +x.release +:: + + + + +anchor::Ex.5:: +subsection::Ex. 5: Non-integer source + +code:: +( +x = { + |lookBack = 3, thr = 1| + var trig = Impulse.ar(7); + // for a non-integer source it makes sense to take a sufficiently large threshold thr + var midi = Demand.ar(trig, 0, DIdev(SinOsc.ar(0.2, 0, 15, 82), 5, -6, 5, lookBack, thr: thr)); + midi.poll(7, label: \midi); + SinOsc.ar(midi.midicps.lag(0.007)) ! 2 * 0.1 +}.play; +) + +// close floats can occur here +x.set(\thr, 0.01) + +// not here +x.set(\thr, 2) + +x.release +:: + + + + +anchor::Ex.6:: +subsection::Ex. 6: Multichannel expansion + +code:: +// nothing especially implemented + +( +x = { + var trig = Impulse.ar(7); + var in = [0, 8.5]; + var maxLookBack = [1, 3]; + var loDev = [-1, -5]; + var hiDev = [1, 5]; + var midi = { |i| Demand.ar(trig, 0, + DIdev( + in[i] + SinOsc.ar(0.1, -pi/2).range(65, 85).round, + maxLookBack: maxLookBack[i], + loDev: loDev[i], + hiDev: hiDev[i] + ).dpoll(label: "midi_" ++ (i == 0).if { "lo" }{ "hi"}) + ) } ! 2; + SinOsc.ar(midi.lag(0.007).midicps, 0, 0.1) +}.play; +) + +x.release +:: + + + +anchor::Ex.7:: +subsection::Ex. 7: Application to other params: rhythm + +code:: +// if we have indexed data for whatever, we can slide over it +// prepare some rhythms in order +// use them for SynthDef + +( +~rhythmBase = [ + [1, 1], + [2, 1, 1], + [1, 1, 2], +].collect(_.normalizeSum); + +~rhythms = ~rhythmBase *.x [1, 2]; +~rhythmNum = ~rhythms.size; +~rhythms = ~rhythms.scramble; + +"rhythm types: ".postln; +~rhythms.do { |r, i| i.post; ": ".post; r.postln }; + +SynthDef(\sine_rhythm, { |out = 0, freq = 400, att = 0.01, rel = 0.1, gate = 1, amp = 0.2| + var trig, loDev = -1, hiDev = 1, sig, src, + rhy = ~rhythmNum.collect { |i| Dseq(~rhythms[i], 1) }; + + trig = TDuty.ar( + Dswitch(rhy, + // be careful not to exceed range of rhythm indices, which can result in server quit + Dpoll( + DIdev(SinOsc.ar(0.1).range(loDev.abs, ~rhythmNum - hiDev - 1).round, 2, loDev, hiDev), + 'rhythm type' + ) + ) * 0.3 + ); + src = SinOsc.ar(Demand.ar(trig, 0, LFDNoise3.ar([0.5, 3], [10, 15], [60, 85])).midicps); + sig = Decay2.ar(trig, att, rel) * src; + Out.ar(out, sig * EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2) * amp); +}).add; +) + +x = Synth(\sine_rhythm) + +x.release +:: + + +anchor::Ex.8:: +subsection::Ex. 8: Proof of concept + +code:: +( +// Function to check an array for repetitions within a maximum test span + +~repetitionCheck = { |array, maxTestSpan| + maxTestSpan.do { |i| + var result = (array.drop(i+1) - array).drop((i+1).neg).includes(0).not; + ("no repetitions within a span of " ++ (i+2).asString ++ " items: ").post; + result.postln; + } +}; + +// prepare buffer to store DIdev values + +n = 10000; // buffer size +r = 10000; // trigger rate +b = Buffer.alloc(s, n); +) + + +// run to store, wait until finished (a bit more than 1 second) +( +{ + var trig = Impulse.ar(r); + Demand.ar(trig, 0, Dbufwr(DIdev(Dbrown(0, 20, 0.3).round, 5, -7, 7), b, Dseries(0, 1, n), 0)); + Line.ar(dur: n / r + 0.1, doneAction: 2); + 0 +}.play; +) + +// move data to language + +b.loadToFloatArray(action: { |x| a = x.asInteger; "array filled \n".postln; }) + + +// no repetitions within a maximum span of 6 (maxLookBack was 5) + +~repetitionCheck.(a, 10); +:: + + +anchor::Ex.9:: +subsection::Ex. 9: Switching signals with DXMix + +code:: +// source of 10 stereo granulations: +// they differ in position movement, trigrate and rate + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + +( +x = { + var pos = { |i| SinOsc.ar(0.02, pi/5 * i).range(0.1, 0.8) } ! 10; + var sig; + + sig = pos.collect { |p, i| + TGrains.ar( + 2, + trigger: Impulse.ar(i * 10 + 30), + bufnum: b, + rate: LFDNoise3.ar(0.1).range(0.3, 1.5), + centerPos: p * BufDur.ir(b), + dur: 0.1, + pan: Dseq([-1, 1], inf) + ) + }; + // switch between stereo sources with DXMix + DXMix.ar( + Dpoll(DIdev(SinOsc.ar(0.1).range(2, 7).round, 2, -2, 1)), + `sig, + fadeMode: 1, + stepTime: 0.03, + fadeTime: 0.002 + ) * 5 +}.play +) + +x.release + + +// sine stereo sources + +( +x = { + var sig = (1..20).scramble.collect { |i| + SinOsc.ar( + [i, 20-i] * 100 * LFDNoise3.ar(0.1).range(0.97, 1.03), + 0, + 0.05 * LFDNoise3.ar(1 ! 2).range(0.1, 1) + ) + }; + DXMix.ar( + Dpoll(DIdev(SinOsc.ar(0.05).range(2, 17).round, 2, -2, 2)), + `sig, + fadeMode: 1, + stepTime: 0.03, + fadeTime: 0.002 + ) ; +}.play +) + +x.release +:: + diff --git a/HelpSource/Classes/DXEnvFan.schelp b/HelpSource/Classes/DXEnvFan.schelp new file mode 100644 index 0000000..050ebcd --- /dev/null +++ b/HelpSource/Classes/DXEnvFan.schelp @@ -0,0 +1,727 @@ +CLASS:: DXEnvFan +summary:: returns crossfade envelopes according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +DXEnvFan returns the multichannel envelope signal, which is used by DXMix / DXMixIn / DXFan / DXFanOut implicitely. It can be used as envelope and trigger at the same time, which leads to applications such as crossfading PlayBufs and different kinds of granulation, using a buffer or not. + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the link::Tutorials/DX_suite:: overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::Classes/DXMix#Ex.2#DXMix, Ex.2:: – width and offset arguments in link::Classes/DXMix#Ex.3#DXMix, Ex.3:: – multichannel expansion in link::Classes/DXMix#Ex.6#DXMix, Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::Classes/DXMix#Ex.8#DXMix, Ex.8:: and link::Classes/DXEnvFan#Ex.2#Ex.2::, link::Classes/DXEnvFan#Ex.4#Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#DXFan, Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + +CLASSMETHODS:: + +method::ar + +argument::out +Determines the sequence of channels between which the envelopes should be crossfaded. A channel index, a demand rate or other ugen returning channel indices or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::out:: and the latter contains demand rate ugens, they must all be wrapped into Functions. + +argument::fadeTime +A fade time, a demand rate or other ugens returning fade times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::fadeTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::fadeTime:: depends on strong::fadeMode::. strong::fadeTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::stepTime +A step time, a demand rate or other ugens returning step times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::stepTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::stepTime:: depends on strong::fadeMode::. strong::stepTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::fadeMode +Integers between 0 and 4 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. +list:: +## fadeMode = 0: only fadeTimes are used, no steps +## fadeMode = 1: alternate steps and fades, begin with step; strong::stepTime:: means time without fade +## fadeMode = 2: alternate fades and steps, begin with fade; strong::stepTime:: means time without fade +## fadeMode = 3: alternate steps and fades, begin with step; strong::stepTime:: means sum of step and fade, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +## fadeMode = 4: alternate fades and steps, begin with fade; strong::stepTime:: means sum of fade and step, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +:: +Defaults to 0. + +argument::sine +Determines the crossfade type: sine-based or not. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::sine:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::sine:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::equalPower +Determines if crossfading of equal power type (square root) should be applied. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::equalPower:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::equalPower:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::power +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude. If power and curve are passed, power applies before. A positive Number or a demand rate or other ugen returning positive strong::power:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::curve +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude according to the lincurve mapping. If power and curve are passed, power applies before. A Number or a demand rate or other ugen returning strong::curve:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::curve:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Calculation of curvature is not giving reliable results when strong::width:: and / or strong::dynOutOffset:: are being modulated at the same time. Defaults to 0. + +argument::allowTypeSeq +Enables sequencing of strong::sine::, strong::equalPower::, strong::power:: and strong::curve:: with demand rate ugens and modulating of strong::sine:: and strong::equalPower:: with other ugens. A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0. + +argument::fadeRate +One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. Defaults to \ar. + +argument::maxFadeNum +Integer determining the maximum number of fades, after which strong::doneAction:: applies. A SequenceableCollection causes multichannel expansion. Not modulatable. Defaults to inf. + +argument::maxWidth +An Integer determining the maximum strong::width:: or a SequenceableCollection of such, causing multichannel expansion, strong::width:: goes into PanAz's width arg. strong::maxWidth:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 2. + +argument::width +Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, causing multichannel expansion. Not modulatable in versions earlier than SC 3.9. It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed strong::maxWidth::. Defaults to 2. + +argument::initOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines an initial offset for PanAz's pos arg. This can be useful for a start with full or reduced width. Not modulatable. Defaults to 0. + +argument::maxDynOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines the maximum strong::dynOutOffset:: to be expected. strong::maxDynOutOffset:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 1. + +argument::dynOutOffset +UGen, Integer or Float or a SequenceableCollection of such, causing multichannel expansion. By passing a ugen the movement between buses can be modulated. Note that a ugen's output must not exceed strong::maxDynOutOffset::. Defaults to 0. + +argument::allowFadeEnd +Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion. Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated trigger logic and more running ugens. If set to 0, the behaviour after the end of strong::in:: is undefined. Defaults to 1. + +argument::size +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the size of the returned multichannel envelope signal. Not modulatable. Defaults to 2. + +argument::bus +Bus, bus index or a SequenceableCollection of such, causing multichannel expansion. Determines whether a private multichannel bus should be used for channel switching. This is recommended for larger width sizes (> 10 or so) as otherwise the number of ugens might result in an overflow error. Not modulatable. Defaults to nil. + +argument::zeroThr +A Number or a ugen returning strong::zeroThr:: numbers or a SequenceableCollection of such, causing multichannel expansion. Determines if output values below this threshold are replaced by 0. This makes sense if the output signal is used as trigger (e.g. with DXEnvFan). In the case of low power numbers small inaccuracies are amplified, this is avoided with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power. As this requires more ugens running in parallel it is disabled by default = nil. + +argument::doneAction +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the doneAction after strong::maxFadeNum:: is exceeded. Defaults to 0. + +method::kr + + +SECTION::Examples + +anchor::Ex.1:: +code:: +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.reboot; +) +:: + + + +subsection::Ex.1: Basic types of crossfades + +code:: +// For normal crossfades the default values - equal power panning of sine type - should be fine, +// other types of crossfade envelopes can be taken for other purposes such as granular synthesis. + + +// default width 2, default equal power crossfading + +// employs crossfading from PanAz, which results in envelopes of sine type, from which +// the square root is taken + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// when dropping equalPower we get the pure sine envelope +// higher width + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + maxWidth: 8, + width: 5.5, + equalPower: 0, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// type sine = 0 switches to a linear curve base, +// with default equalPower = 1 this leads to a square root envelope + + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + sine: 0, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// a linear curve base without equalPower means a linear crossfade + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + sine: 0, + equalPower: 0, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// if equalPower is set to 0 you can choose a power +// check alternative values for sine and power also + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + equalPower: 0, + sine: 0, // 1 + power: 3, // 0.3 + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// power can be a ugen too + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + equalPower: 0, + sine: 1, // 1 + power: SinOsc.ar(10, -pi/2).range(0.5, 10), + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// if equalPower is set to 0 you can also choose a curve arg +// which is passed as curvature to lincurve + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + equalPower: 0, + curve: 3, // -3 + sine: 0, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// curve can be a ugen too + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + curve: Line.ar(5, -5, 0.1), // -3 + sine: 0, + equalPower: 0, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// Passing a dynOutOffset arg - wobbled sliding + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + dynOutOffset: SinOsc.ar(150).range(0, 1), + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// This is not recommended: +// With dynOutOffset or modulated width a curve arg leads to irregularities + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + dynOutOffset: SinOsc.ar(150).range(0, 1), + equalPower: 0, + curve: 1, + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// out can also be a ugen, but note that with equalPower (default) +// blending the same channel leads to amplitude pikes, +// to avoid that take a linear crossfade + +( +{ + DXEnvFan.ar( + LFDNoise3.ar(15).range(0, 7), + size: 8, + fadeTime: 0.01, + stepTime: 0.02, + fadeMode: 1, + sine: 0, + equalPower: 1 // compare 0 + ) +}.plot(1) +) +:: + + +anchor::Ex.2:: +subsection::Ex.2: Sequencing crossfade types and parameters + +code:: +// sequencing crossfade types and parameters must be allowed explicitely as +// it is more CPU-costly + +// alternate linear and pure sine +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + allowTypeSeq: 1, + sine: Dseq([0, 1], inf), + equalPower: 0, // Dseq([0, 1], inf) + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + + +// curvature sequencing + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + allowTypeSeq: 1, + sine: 0, + equalPower: 0, + curve: Dseq([-3, -3, 3, 3], inf), + // fadeMode: 1, + // stepTime: 0.015 + ) +}.plot(0.1) +) + +:: + + +anchor::Ex.3:: +subsection::Ex.3: The 'zeroThr' arg + +code:: +// There might occur small inaccuracies in the calculation of crossfade values. +// This is irrelevant in most cases, but if you use the output signal as trigger +// it is definitely unwanted. +// You can supress such if you set an appropriate zero threshold. + + +// The effect of unwanted envelope segments especially becomes apparent +// with small power values that blow up values near 0. +// Values below the zeroThr are set to 0 before applying power or curvature. + +// Compare version without passing zeroThr. + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + equalPower: 0, + sine: 0, + power: 0.3, + fadeMode: 1, + stepTime: 0.015, + zeroThr: 0.002 + ) +}.plot(0.3) +) +:: + + +anchor::Ex.4:: +subsection::Ex.4: The 'bus' arg + +code:: +// As channel switching with DXEnvFan / DXFan is implemented by "watcher ugens", +// it becomes costly if the number of output channels increases (growth of quadratic order). +// The effort is lowered significantly if you pass a reserved bus for this or use DXEnvFanOut, +// this also concerns DXFan / DXFanOut. + +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numPrivateAudioBusChannels = 256; +s.options.memSize = 8192 * 4; +s.options.numWireBufs = 512; +s.reboot; +) + + +// on my machine this example needs ca. 2.5 % CPU (818 ugens) ... + +( +x = { +    DXEnvFan.ar( +        Dshuf((0..29), inf), +        size: 30, +        fadeTime: 0.005 +    ) * 0.25 +}.play +) + +x.release + +// ... whereas this needs ca. 0.6 % CPU (167 ugens) + +( +a = Bus.audio(s, 30); + +x = { +    DXEnvFan.ar( +        Dshuf((0..29), inf), +        size: 30, +        fadeTime: 0.005, +        bus: a +    ) * 0.25 +}.play +) + +x.release + +( +a.free; +b.free; +) + + + +// care has to be taken with buses and multichannel expansion: + +// here two buses have to passed as otherwise we get a wrong result, +// the same bus would be taken for different calculations at the same time + +( +a = Bus.audio(s, 8); +b = Bus.audio(s, 8); + +{ + Mix(DXEnvFan.ar( + [Dseq((0..7), inf), Dseq((7..0), inf)], + size: 8, + fadeTime: 0.01, + equalPower: 0, + bus: [a, b] + )) +}.plot(0.1) +) + +( +a.free; +b.free; +) +:: + + +anchor::Ex.5:: +subsection::Ex.5: PlayBuf crossfading + +code:: +// Here a two channel envelope signal is used to crossfade between +// two channels of a PlayBuf, as rates are close we get a trill effect. + +// Note that the envelope signal is used three times: + +// as a trigger to the startPos within PlayBuf +// as a trigger for the demand ugen that determines the startPos within PlayBuf +// as an envelope for the PlayBuf + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + +( +x = { + var sig, env = DXEnvFan.ar( + Dseq([0, 1], inf), + fadeMode: 3, + stepTime: 0.05, + fadeTime: 0.01, + // to ensure right triggering set zeroThr + zeroThr: 0.002 + ); + + sig = PlayBuf.ar( + 1, + b, + [1, 1.1] * BufRateScale.kr(b), + env, + Demand.ar( + env, + 0, + Dstutter( + 5, + Dwhite(0.1, 0.9) + ) * BufFrames.ir(b) + ) + ) * 1.2 * env; + // do a bit correlation + Splay.ar(sig, 0.8) +}.play +) + +x.release + + +// L and R get different mixes, +// both take the same envelope trigger which switches +// between PlayBufs of different rates, the difference between L and R +// comes from different random start positions. + +( +x = { + var buf, env = DXEnvFan.ar( + Dseq([Dshuf((0..4)), Dshuf((5..7))], inf), + size: 8, + fadeMode: 3, + stepTime: 0.2, + fadeTime: 0.02, + zeroThr: 0.002 + ); + + { + Mix(PlayBuf.ar( + 1, + b, + { |j| j / 4 + 0.3 } ! 8 * BufRateScale.kr(b), + env, + Demand.ar(env, 0, Drand((2..5)/10, inf) * BufFrames.ir(b)), + loop: 0, + ) * env) + } ! 2 ; +}.play +) + + +x.release + +// variant with multichannel expansion +// two 8 ch trigger envelopes are used for L and R mixes +( +x = { + var buf, env = DXEnvFan.ar( + [Dseq((0..7), inf), Diwhite(0, 7)], + size: 8, + fadeMode: 3, + stepTime: 0.2, + fadeTime: 0.02, + zeroThr: 0.002 + ); + + { |i| Mix(PlayBuf.ar( + 1, + b, + { |j| j / 4 + 0.3 } ! 8 * BufRateScale.kr(b), + env[i], + // same positions go parallel + Demand.ar(env[i], 0, Dstutter(8, Dseq((2..5)/10, inf)) * BufFrames.ir(b)), + loop: 0, + ) * env[i]) } ! 2 ; +}.play +) + +x.release +:: + + +anchor::Ex.6:: +subsection::Ex.6: Granulation, sequencing of fxs and fx parameters per grain + +code:: +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + +// sequencing of band pass frequency +// see also Buffer Granulation tutorial, Ex. 1f + +( +a = Bus.audio(s, 8); + +x = { + var sig, env = DXEnvFan.ar( + Dseq((0..7), inf), + size: 8, + maxWidth: 8, + width: 5, + fadeTime: 0.01, + // to ensure right triggering set zeroThr + zeroThr: 0.002, + bus: a + ); + + sig = PlayBuf.ar( + 1, + b, + BufRateScale.kr(b), + env, + Demand.ar(env, 0, Dbrown(0.2, 0.5, 0.0025) * BufFrames.ir(b)), + loop: 0, + ) * env; + + // multichannel trigger polls from single sequencing source + // ensure non-zero filter freq for later triggers with max + sig = BPF.ar(sig, Demand.ar(env, 0, Dbrown(200, 2000, 100)).max(200), 0.1); + + // do a bit correlation + Splay.ar(sig, 0.6) * 7 +}.play +) + +x.release + +a.free + + + +// sequencing of different fxs + +( +a = Bus.audio(s, 8); + +x = { + var sig, env = DXEnvFan.ar( + Drand((0..7), inf), + size: 8, + maxWidth: 8, + // oscillation of overlap + width: LFDNoise3.ar(1).range(2, 6), + fadeTime: 0.015, + // to ensure right triggering set zeroThr + zeroThr: 0.002, + bus: a + ); + + sig = PlayBuf.ar( + 1, + b, + BufRateScale.kr(b), + env, + Demand.ar(env, 0, Dbrown(0.2, 0.5, 0.005) * BufFrames.ir(b)), + loop: 0, + ) * env; + + // selection of fxs as well as fx params triggered with envelope + // ring modulation, bit crusher and band pass + sig = Select.ar(Demand.ar(env, 0, Dstutter(Diwhite(5, 30), Dxrand([0, 1, 2], inf))), [ + sig * SinOsc.ar(Demand.ar(env, 0, Dbrown(250, 1000, 200))) * 1.5, + sig.round(2 ** Demand.ar(env, 0, Dbrown(-1, -4, 1))).lag(0.005) * 1.5, + // ensure non-zero filter freq for later triggers with max + BPF.ar(sig, Demand.ar(env, 0, Dbrown(200, 2000, 200)).max(200), 0.2) * 5 + ]); + + // do a bit correlation + Splay.ar(sig, 0.6) +}.play +) + +x.release + +a.free +:: + + +anchor::Ex.7:: +subsection::Ex.7: Multichannel expansion + +code:: + +// Not as complicated options as with DXMix +// we get an array of multichannel envelopes, here a mix of them + +( +{ + Mix(DXEnvFan.ar( + (0..3).collect { |i| Dseq((0..3).rotate(i), inf) }, + fadeTime: [0.01, 0.05], + size: 4, + width: 1 + )) +}.plot(0.2) +) + +// see Ex.4 for a delicate case with bus args +:: + + diff --git a/HelpSource/Classes/DXEnvFanOut.schelp b/HelpSource/Classes/DXEnvFanOut.schelp new file mode 100644 index 0000000..83858e6 --- /dev/null +++ b/HelpSource/Classes/DXEnvFanOut.schelp @@ -0,0 +1,222 @@ +CLASS:: DXEnvFanOut +summary:: sends crossfade envelopes to out buses according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +DXEnvFanOut sends multichannel envelopes, which are used by DXMix / DXMixIn / DXFan / DXFanOut implicitely, to a sequence of out buses, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. It can be used as envelope and trigger at the same time, which leads to applications such as crossfading PlayBufs and different kinds of granulation, using a buffer or not. + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the link::Tutorials/DX_suite:: overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::Classes/DXMix#Ex.2#DXMix, Ex.2:: – width and offset arguments in link::Classes/DXMix#Ex.3#DXMix, Ex.3:: – multichannel expansion in link::Classes/DXMix#Ex.6#DXMix, Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#DXEnvFan, Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::Classes/DXMix#Ex.8#DXMix, Ex.8:: and link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2::, link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#DXFan, Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + +CLASSMETHODS:: + +method::ar + +argument::out +Determines the sequence of buses between which the envelope should be crossfaded. A bus index, a demand rate or other ugen returning bus indices or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::out:: and the latter contains demand rate ugens, they must all be wrapped into Functions. + +argument::fadeTime +A fade time, a demand rate or other ugens returning fade times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::fadeTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::fadeTime:: depends on strong::fadeMode::. strong::fadeTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::stepTime +A step time, a demand rate or other ugens returning step times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::stepTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::stepTime:: depends on strong::fadeMode::. strong::stepTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::fadeMode +Integers between 0 and 4 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. +list:: +## fadeMode = 0: only fadeTimes are used, no steps +## fadeMode = 1: alternate steps and fades, begin with step; strong::stepTime:: means time without fade +## fadeMode = 2: alternate fades and steps, begin with fade; strong::stepTime:: means time without fade +## fadeMode = 3: alternate steps and fades, begin with step; strong::stepTime:: means sum of step and fade, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +## fadeMode = 4: alternate fades and steps, begin with fade; strong::stepTime:: means sum of fade and step, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +:: +Defaults to 0. + +argument::sine +Determines the crossfade type: sine-based or not. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::sine:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::sine:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::equalPower +Determines if crossfading of equal power type (square root) should be applied. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::equalPower:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::equalPower:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::power +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude. If power and curve are passed, power applies before. A positive Number or a demand rate or other ugen returning positive strong::power:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::curve +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude according to the lincurve mapping. If power and curve are passed, power applies before. A Number or a demand rate or other ugen returning strong::curve:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::curve:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Calculation of curvature is not giving reliable results when strong::width:: and / or strong::dynOutOffset:: are being modulated at the same time. Defaults to 0. + +argument::allowTypeSeq +Enables sequencing of strong::sine::, strong::equalPower::, strong::power:: and strong::curve:: with demand rate ugens and modulating of strong::sine:: and strong::equalPower:: with other ugens. A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0. + +argument::fadeRate +One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. Defaults to \ar. + +argument::maxFadeNum +Integer determining the maximum number of fades, after which strong::doneAction:: applies. A SequenceableCollection causes multichannel expansion. Not modulatable. Defaults to inf. + +argument::maxWidth +An Integer determining the maximum strong::width:: or a SequenceableCollection of such, causing multichannel expansion, strong::width:: goes into PanAz's width arg. strong::maxWidth:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 2. + +argument::width +Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, causing multichannel expansion. Not modulatable in versions earlier than SC 3.9. It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed strong::maxWidth::. Defaults to 2. + +argument::initOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines an initial offset for PanAz's pos arg. This can be useful for a start with full or reduced width. Not modulatable. Defaults to 0. + +argument::maxDynOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines the maximum strong::dynOutOffset:: to be expected. strong::maxDynOutOffset:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 1. + +argument::dynOutOffset +UGen, Integer or Float or a SequenceableCollection of such, causing multichannel expansion. By passing a ugen the movement between buses can be modulated. Note that a ugen's output must not exceed strong::maxDynOutOffset::. Defaults to 0. + +argument::allowFadeEnd +Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion. Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated trigger logic and more running ugens. If set to 0, the behaviour after the end of strong::in:: is undefined. Defaults to 1. + +argument::zeroThr +A Number or a ugen returning strong::zeroThr:: numbers or a SequenceableCollection of such, causing multichannel expansion. Determines if output values below this threshold are replaced by 0. This makes sense if the output signal is used as trigger (e.g. with DXEnvFan). In the case of low power numbers small inaccuracies are amplified, this is avoided with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power. As this requires more ugens running in parallel it is disabled by default = nil. + +argument::doneAction +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the doneAction after strong::maxFadeNum:: is exceeded. Defaults to 0. + +method::kr + + +SECTION::Examples + +note:: +As with DXFan / DXFanOut examples from DXEnvFan help also can be written with DXEnvFanOut, but the latter doesn't need size and bus args as out buses are addressed directly. There is a small difference also with multichannel expansion, see last example below. +:: + + +anchor::Ex.1:: +code:: +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.reboot; +) +:: + + +subsection::Ex.1: Basic usage + +code:: +// play SinOscs silently and wait for granulation envelopes + +( +a = Bus.audio(s, 10); +x = { Splay.ar(In.ar(a, 10) * SinOsc.ar((3..12) * 100, 0, 0.05)) }.play +) + + +// send envelopes to buses + +( +z = { + DXEnvFanOut.ar( + Dseq((0..5) + a.index, inf) + Diwhite(1, 4), + + // with newer SC versions you can also write: + // Dseq((0..5), inf) + Diwhite(1, 4) + a.index, + + fadeTime: 0.05, + width: 1, + initOutOffset: -0.5 + ) +}.play +) + +x.release; + +// cleanup + +( +z.free; +a.free; +) +:: + + + +anchor::Ex.2:: +subsection::Ex.2: Multichannel expansion + +code:: +// play SinOscs silently and wait for granulation envelopes + +( +a = Bus.audio(s, 10); +x = { Splay.ar(In.ar(a, 10) * SinOsc.ar((3..12) * 100, 0, 0.05)) }.play +) + +// send envelope to buses in parallel + +( +z = { + DXEnvFanOut.ar( + [0, 3] + Dseq((0..3) + a.index, inf) + Diwhite(0, 3), + + // with newer SC versions you can also write: + // [0, 3] + Dseq((0..3), inf) + Diwhite(0, 3) + a.index, + + fadeTime: 0.05, + width: 1, + initOutOffset: -0.5 + ) +}.play +) + +x.release; + +// cleanup + +( +z.free; +a.free; +) + + +// Ex.7 from DXEnvFan help looks a bit different, +// as DXEnvFanOut is an out ugen we don't need to mix + +( +a = Bus.audio(s, 4); +{ + DXEnvFanOut.ar( + (0..3).collect { |i| Dseq((0..3).rotate(i), inf) } + a.index, + fadeTime: [0.01, 0.05], + width: 1 + ); + In.ar(a, 4) +}.plot(0.2) +) + +a.free +:: + diff --git a/HelpSource/Classes/DXFan.schelp b/HelpSource/Classes/DXFan.schelp new file mode 100644 index 0000000..6d9e7ed --- /dev/null +++ b/HelpSource/Classes/DXFan.schelp @@ -0,0 +1,327 @@ +CLASS:: DXFan +summary:: crossfades signals within a multichannel array according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +DXFan crossfades signals to a sequence of channels, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the link::Tutorials/DX_suite:: overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::Classes/DXMix#Ex.2#DXMix, Ex.2:: – width and offset arguments in link::Classes/DXMix#Ex.3#DXMix, Ex.3:: – multichannel expansion in link::Classes/DXMix#Ex.6#DXMix, Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#DXEnvFan, Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::Classes/DXMix#Ex.8#DXMix, Ex.8:: and link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2::, link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + +CLASSMETHODS:: + +method::ar + +argument::out +Determines the sequence of channels between which the signal should be crossfaded. A channel index, a demand rate or other ugen returning channel indices or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::out:: and the latter contains demand rate ugens, they must all be wrapped into Functions. + +argument::channelsArrayRef +The signal to be crossfaded. A single channel can be passed as such, an array must be wrapped into a Ref object to avoid multichannel expansion. In this case the multichannel signal is crossfaded from one block of adjacent channels to the next, whereby the lowest channel index follows the base sequence defined by out. A SequenceableCollection causes multichannel expansion, whereby single items of the collection can itself be Ref objects containing multichannel signals. + +argument::fadeTime +A fade time, a demand rate or other ugens returning fade times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::fadeTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::fadeTime:: depends on strong::fadeMode::. strong::fadeTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::stepTime +A step time, a demand rate or other ugens returning step times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::stepTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::stepTime:: depends on strong::fadeMode::. strong::stepTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::fadeMode +Integers between 0 and 4 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. +list:: +## fadeMode = 0: only fadeTimes are used, no steps +## fadeMode = 1: alternate steps and fades, begin with step; strong::stepTime:: means time without fade +## fadeMode = 2: alternate fades and steps, begin with fade; strong::stepTime:: means time without fade +## fadeMode = 3: alternate steps and fades, begin with step; strong::stepTime:: means sum of step and fade, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +## fadeMode = 4: alternate fades and steps, begin with fade; strong::stepTime:: means sum of fade and step, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +:: +Defaults to 0. + +argument::sine +Determines the crossfade type: sine-based or not. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::sine:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::sine:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::equalPower +Determines if crossfading of equal power type (square root) should be applied. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::equalPower:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::equalPower:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::power +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude. If power and curve are passed, power applies before. A positive Number or a demand rate or other ugen returning positive strong::power:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::curve +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude according to the lincurve mapping. If power and curve are passed, power applies before. A Number or a demand rate or other ugen returning strong::curve:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::curve:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Calculation of curvature is not giving reliable results when strong::width:: and / or strong::dynOutOffset:: are being modulated at the same time. Defaults to 0. + +argument::allowTypeSeq +Enables sequencing of strong::sine::, strong::equalPower::, strong::power:: and strong::curve:: with demand rate ugens and modulating of strong::sine:: and strong::equalPower:: with other ugens. A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0. + +argument::fadeRate +One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. Defaults to \ar. + +argument::maxFadeNum +Integer determining the maximum number of fades, after which strong::doneAction:: applies. A SequenceableCollection causes multichannel expansion. Not modulatable. Defaults to inf. + +argument::maxWidth +An Integer determining the maximum strong::width:: or a SequenceableCollection of such, causing multichannel expansion, strong::width:: goes into PanAz's width arg. strong::maxWidth:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 2. + +argument::width +Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, causing multichannel expansion. Not modulatable in versions earlier than SC 3.9. It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed strong::maxWidth::. Defaults to 2. + +argument::initOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines an initial offset for PanAz's pos arg. This can be useful for a start with full or reduced width. Not modulatable. Defaults to 0. + +argument::maxDynOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines the maximum strong::dynOutOffset:: to be expected. strong::maxDynOutOffset:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 1. + +argument::dynOutOffset +UGen, Integer or Float or a SequenceableCollection of such, causing multichannel expansion. By passing a ugen the movement between buses can be modulated. Note that a ugen's output must not exceed strong::maxDynOutOffset::. Defaults to 0. + +argument::allowFadeEnd +Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion. Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated trigger logic and more running ugens. If set to 0, the behaviour after the end of strong::in:: is undefined. Defaults to 1. + +argument::size +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the size of the returned multichannel signal. Not modulatable. Defaults to 2. + +argument::bus +Bus, bus index or a SequenceableCollection of such, causing multichannel expansion. Determines whether a private multichannel bus should be used for channel switching. This is recommended for larger width sizes (> 10 or so) as otherwise the number of ugens might result in an overflow error. Not modulatable. Defaults to nil. + +argument::zeroThr +A Number or a ugen returning strong::zeroThr:: numbers or a SequenceableCollection of such, causing multichannel expansion. Determines if output values below this threshold are replaced by 0. This makes sense if the output signal is used as trigger (e.g. with DXEnvFan). In the case of low power numbers small inaccuracies are amplified, this is avoided with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power. As this requires more ugens running in parallel it is disabled by default = nil. + +argument::doneAction +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the doneAction after strong::maxFadeNum:: is exceeded. Defaults to 0. + +method::kr + + +SECTION::Examples + +note:: +Note that, as with DXEnvFan, higher values passed to 'size' and 'maxWidth' cause a significant growth of the number of used ugens. In this case consider passing a bus arg or the use of link::Classes/DXFanOut::, see link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4::. +:: + + +anchor::Ex.1:: +code:: +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.reboot; +) +:: + + +subsection::Ex.1: Basic usage: simple crossfade + +code:: +// crossfading a mono source between two outs + +( +x = { + DXFan.ar( + Dseq([0, 1], inf), + PinkNoise.ar(0.05), + fadeTime: 1 + ) +}.play +) + +x.release + + +// Crossfading a stereo source between two outs, +// for more than two channels size has to be passed. + +( +{ + DXFan.ar( + Dseq([0, 2], inf), + `(Saw.ar(50 * [1, 5], 0.03)), + size: 4, + fadeTime: 0.1 + ) +}.plot(0.2) +) + + +// crossfading a mono source between several outs + +( +{ + DXFan.ar( + Dseq([0, 3, 1, 2], inf), + BPF.ar(PinkNoise.ar(), LFDNoise3.ar(1).range(100, 2000), 0.1, 0.7), + size: 4, + fadeTime: 0.05 + ) +}.plot(0.2) +) + + +// sliding over several channels, increased width + +( +{ + DXFan.ar( + Dseq([0, 3, 1, 2], inf), + BPF.ar(PinkNoise.ar(), LFDNoise3.ar(1).range(100, 2000), 0.1, 0.7), + size: 4, + fadeTime: 0.02, + maxWidth: 4, + width: 3 + ) +}.plot(0.2) +) +:: + + + + +anchor::Ex.2:: +subsection::Ex.2: Multichannel expansion + +code:: +// crossfading mono sources to alternate channels +// note that the result of DXFan, due to multichannel expansion, +// is an array of two stereo arrays which is then mixed to one stereo array. + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + Mix(DXFan.ar( + [Dseq([0, 1], inf), Dseq([1, 0], inf)], + [ + LFTri.ar(150 * lfo.().range(1, 2), 0, 0.05), + BPF.ar(PinkNoise.ar(), lfo.().range(1000, 3000), 0.1, 0.7) + ], + fadeTime: 0.07, + width: 1 + )) +}.play +) + +x.release + + +// crossfading stereo sources to channel pairs (4ch), polyrhythm of fadeTimes. +// Similar to the above example the result of DXFan, due to multichannel expansion, +// is an array of two 4-channel arrays which is then mixed to one 4-channel array. + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + Mix(DXFan.ar( + [Dseq([0, 2], inf), Dseq([2, 0], inf)], + [ + `({ |i| LFTri.ar(150 * lfo.().range(0.5, 2), 0, 0.05) } ! 2) , + `({ |i| BPF.ar(PinkNoise.ar(), lfo.().range(500, 1500) * (i + 1), 0.1, 0.7) } ! 2) + ], + size: 4, + fadeTime: [Dseq([0.06, 0.06, 0.03], inf), Dseq([0.05, 0.05, 0.17], inf)], + width: 1 + )) +}.play; +) + +x.release +:: + + + +anchor::Ex.3:: +subsection::Ex.3: Granulation by crossfading to different channels + +code:: +// mono source crossfaded to 8 channels + +( +{ + var lfo = LFDNoise3.kr(0.2); + DXFan.ar( + Dshuf((0..7), inf), + SinOsc.ar(lfo.range(800, 1500), 0, 0.03), + size: 8, + fadeTime: 0.01 + ) +}.plot(0.2) +) + + +// crossfading stereo pairs to every second out + +( +{ + var lfo = LFDNoise3.kr(0.2); + DXFan.ar( + Dseq((0, 2..6), inf), + `(SinOsc.ar(lfo.range(800, 1500) * [1, 1.02], 0, 0.03)), + size: 8, + fadeTime: 0.01 + ) ; +}.plot(0.2) +) +:: + + +anchor::Ex.4:: +subsection::Ex.4: Granulation with high trigger rates and / or short grain durations + +code:: +// fadeTimes should be above blockSize +// for shorter grains you can use smaller blocksizes + +( +s.options.blockSize = 2; +s.reboot; +) + +// as the effect is AM on single outs we get side bands + +( +s.doWhenBooted { + x = { + var lfo = LFDNoise3.ar(0.2); + DXFan.ar( + Dseq((0..7), inf), + SinOsc.ar(lfo.range(800, 1500), 0, 0.03), + size: 8, + fadeTime: 0.0002 + ) + }.play +}; +) + +x.release + + +// go back to default + +( +s.options.blockSize = 64; +s.reboot; +) +:: + + diff --git a/HelpSource/Classes/DXFanOut.schelp b/HelpSource/Classes/DXFanOut.schelp new file mode 100644 index 0000000..d910575 --- /dev/null +++ b/HelpSource/Classes/DXFanOut.schelp @@ -0,0 +1,273 @@ +CLASS:: DXFanOut +summary:: crossfades signals between out buses according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +DXFanOut crossfades signals to a sequence of out buses, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the link::Tutorials/DX_suite:: overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::Classes/DXMix#Ex.2#DXMix, Ex.2:: – width and offset arguments in link::Classes/DXMix#Ex.3#DXMix, Ex.3:: – multichannel expansion in link::Classes/DXMix#Ex.6#DXMix, Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#DXEnvFan, Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::Classes/DXMix#Ex.8#DXMix, Ex.8:: and link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2::, link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#DXFan, Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + +CLASSMETHODS:: + +method::ar + +argument::out +Determines the sequence of buses between which the envelope should be crossfaded. A bus index, a demand rate or other ugen returning bus indices or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::out:: and the latter contains demand rate ugens, they must all be wrapped into Functions. + +argument::channelsArrayRef +The signals to be crossfaded. A single channel doesn't can be passed as such, an array must be wrapped into a Ref object to avoid multichannel expansion. In this case the multichannel signal is crossfaded from one block of adjacent buses to the next, whereby the lowest bus index follows the base sequence defined by out. A SequenceableCollection causes multichannel expansion, whereby single items of the collection can itself be Ref objects containing multichannel signals. + + +argument::fadeTime +A fade time, a demand rate or other ugens returning fade times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::fadeTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::fadeTime:: depends on strong::fadeMode::. strong::fadeTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::stepTime +A step time, a demand rate or other ugens returning step times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::stepTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::stepTime:: depends on strong::fadeMode::. strong::stepTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::fadeMode +Integers between 0 and 4 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. +list:: +## fadeMode = 0: only fadeTimes are used, no steps +## fadeMode = 1: alternate steps and fades, begin with step; strong::stepTime:: means time without fade +## fadeMode = 2: alternate fades and steps, begin with fade; strong::stepTime:: means time without fade +## fadeMode = 3: alternate steps and fades, begin with step; strong::stepTime:: means sum of step and fade, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +## fadeMode = 4: alternate fades and steps, begin with fade; strong::stepTime:: means sum of fade and step, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +:: +Defaults to 0. + +argument::sine +Determines the crossfade type: sine-based or not. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::sine:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::sine:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::equalPower +Determines if crossfading of equal power type (square root) should be applied. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::equalPower:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::equalPower:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::power +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude. If power and curve are passed, power applies before. A positive Number or a demand rate or other ugen returning positive strong::power:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::curve +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude according to the lincurve mapping. If power and curve are passed, power applies before. A Number or a demand rate or other ugen returning strong::curve:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::curve:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Calculation of curvature is not giving reliable results when strong::width:: and / or strong::dynOutOffset:: are being modulated at the same time. Defaults to 0. + +argument::allowTypeSeq +Enables sequencing of strong::sine::, strong::equalPower::, strong::power:: and strong::curve:: with demand rate ugens and modulating of strong::sine:: and strong::equalPower:: with other ugens. A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0. + +argument::fadeRate +One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. Defaults to \ar. + +argument::maxFadeNum +Integer determining the maximum number of fades, after which strong::doneAction:: applies. A SequenceableCollection causes multichannel expansion. Not modulatable. Defaults to inf. + +argument::maxWidth +An Integer determining the maximum strong::width:: or a SequenceableCollection of such, causing multichannel expansion, strong::width:: goes into PanAz's width arg. strong::maxWidth:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 2. + +argument::width +Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, causing multichannel expansion. Not modulatable in versions earlier than SC 3.9. It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed strong::maxWidth::. Defaults to 2. + +argument::initOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines an initial offset for PanAz's pos arg. This can be useful for a start with full or reduced width. Not modulatable. Defaults to 0. + +argument::maxDynOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines the maximum strong::dynOutOffset:: to be expected. strong::maxDynOutOffset:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 1. + +argument::dynOutOffset +UGen, Integer or Float or a SequenceableCollection of such, causing multichannel expansion. By passing a ugen the movement between buses can be modulated. Note that a ugen's output must not exceed strong::maxDynOutOffset::. Defaults to 0. + +argument::allowFadeEnd +Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion. Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated trigger logic and more running ugens. If set to 0, the behaviour after the end of strong::in:: is undefined. Defaults to 1. + +argument::zeroThr +A Number or a ugen returning strong::zeroThr:: numbers or a SequenceableCollection of such, causing multichannel expansion. Determines if output values below this threshold are replaced by 0. This makes sense if the output signal is used as trigger (e.g. with DXEnvFan). In the case of low power numbers small inaccuracies are amplified, this is avoided with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power. As this requires more ugens running in parallel it is disabled by default = nil. + +argument::doneAction +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the doneAction after strong::maxFadeNum:: is exceeded. Defaults to 0. + +method::kr + + +SECTION::Examples + +note:: +Examples from DXFan help also can be written with DXFanOut, but the latter doesn't need a size arg as the out bus is addressed directly. There is a small difference also with multichannel expansion, see example below. +:: + + +anchor::Ex.1:: +code:: +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.reboot; +) +:: + + +subsection::Ex.1: Multichannel expansion + +code:: +// Compare with Ex. 2 from DXFan help. +// As DXFanOut, other than DXFan, doesn't return an array, a mix is not necessary, +// by internal use of Out ugens the signal is mixed to the referred buses anyway. + +// For the same reason a normal release doesn't work, to get this option we can add an EnvGate. + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + DXFanOut.ar( + [Dseq([0, 1], inf), Dseq([1, 0], inf)], + [ + LFTri.ar(150 * lfo.().range(1, 2), 0, 0.05), + BPF.ar(PinkNoise.ar(), lfo.().range(1000, 3000), 0.1, 0.7) + ] * EnvGate(), + fadeTime: 0.07, + width: 1 + ) +}.play +) + +x.release +:: + + + +anchor::Ex.2:: +subsection::Ex.2: Fast crossfading between fx processings ("fx granulation") + +code:: +// To be distinguished by fx processing of grains! +// define fxs to read from buses + +( +a = Bus.audio(s, 6); + +SynthDef(\resample, { |out = 0, in, lfoFreq = 0.2, resampleLo = 500, resampleHi = 2000, + lag = 0.001, mix = 1, amp = 0.1| + var sig, inSig = In.ar(in, 2), lfo; + lfo = LFDNoise3.kr(lfoFreq).range(resampleLo, resampleHi); + sig = Latch.ar(inSig, Impulse.ar(lfo)).lag(lag); + Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp); +}).add; + +SynthDef(\ring, { |out = 0, in, lfoFreq = 0.2, modFreqLo = 50, modFreqHi = 2000, + mix = 1, amp = 0.1| + var sig, mod, lfo, src, inSig = In.ar(in, 2); + lfo = LFDNoise3.kr(lfoFreq).range(modFreqLo, modFreqHi); + mod = SinOsc.ar(lfo); + sig = inSig * mod; + Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp); +}).add; + +SynthDef(\rectifier, { |out = 0, in, amount = 0, mix = 1, amp = 0.1| + var sig, inSig = In.ar(in, 2); + // need collect as if ugen doesn't take arrays + sig = inSig.collect { |x,i| x.ceil.if(x, x.abs * amount) }; + Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp); +}).add; +) + +// start fxs first +( +u = Synth(\resample, [in: a.subBus(0, 2)]); +v = Synth(\ring, [in: a.subBus(2, 2)]); +w = Synth(\rectifier, [in: a.subBus(4, 2)]); +) + + +// start source, crossfade between fx buses +// play with MouseX, fx and source period are in integer relation + +( +x = { + var seq = Demand.kr( + Impulse.kr(5), + 0, + Dxrand([60, 62, 65.5, 66, 68.5], inf) + Drand([-12, 0, 12], inf) + ).midicps.lag(0.015); + + DXFanOut.ar( + Dseq([0, 1, 2], inf) * 2 + a.index, + `(SinOsc.ar( + seq * [1, 1.01], + 0, + 1 + ) * EnvGate()), + fadeTime: 0.2 / (MouseX.kr(5, 25).round.poll), + width: 1.2 + ) +}.play +) + + +// cleanup + +x.release; + +[u, v, w].do(_.free); + + + +// granulated source + fast fx crossfades + +// load sound file + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + + +// start fxs first +( +u = Synth(\resample, [in: a.subBus(0, 2), lag: 0.01, mix: 0.6]); +v = Synth(\ring, [in: a.subBus(2, 2), mix: 1]); +) + +// feed DXFanOut with granulated signal +// control two trigger rates with MouseX and MouseY +( +x = { + var trig = Impulse.ar(MouseY.kr(20, 100).poll(2, label: 'source trigrate')); + var pos = BufDur.kr(b) * LFDNoise3.ar(0.6).range(0.1, 0.5); + var sig = TGrains.ar(2, trig, b, 1, pos, 0.5, Dseq([-1, 1], inf) * 0.8, 3); + DXFanOut.ar( + Dseq([0, 2], inf) + a.index, + `(sig * EnvGate()), + fadeTime: 0.2 / (MouseX.kr(5, 100).round.poll(2, label: 'fx trigrate')), + width: 1.5 + ) +}.play +) + +// cleanup + +x.release; + +[u, v].do(_.free); + +a.free; +:: + diff --git a/HelpSource/Classes/DXMix.schelp b/HelpSource/Classes/DXMix.schelp new file mode 100644 index 0000000..30bafdf --- /dev/null +++ b/HelpSource/Classes/DXMix.schelp @@ -0,0 +1,988 @@ +CLASS:: DXMix +summary:: crossfades between signals according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/DX_suite, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +DXMix crossfades between signals according to a sequence of indices, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. + + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the link::Tutorials/DX_suite:: overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::#Ex.2#Ex.2:: – width and offset arguments in link::#Ex.3#Ex.3:: – multichannel expansion in link::#Ex.6#Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#DXEnvFan, Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::#Ex.8#Ex.8:: and link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2::, link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#DXFan, Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + + +CLASSMETHODS:: + +method::ar + +argument::in +Determines the sequence of signals to be crossfaded. A demand rate or other ugen returning channel array indices, a single channel array index or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::in:: and the latter contains demand rate ugens, they must all be wrapped into Functions. + +argument::channelsArrayRef +The signals to be crossfaded. To avoid multichannel expansion of this arg, the signals to be crossfaded must be wrapped into a Ref object. If the Ref object contains an array of signal arrays, these arrays are crossfaded. A SequenceableCollection causes multichannel expansion, whereby single items of the collection can itself be Ref objects containing multichannel signals. See multichannel examples below. + +argument::fadeTime +A fade time, a demand rate or other ugens returning fade times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::fadeTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::fadeTime:: depends on strong::fadeMode::. strong::fadeTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::stepTime +A step time, a demand rate or other ugens returning step times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::stepTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::stepTime:: depends on strong::fadeMode::. strong::stepTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::fadeMode +Integers between 0 and 4 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. +list:: +## fadeMode = 0: only fadeTimes are used, no steps +## fadeMode = 1: alternate steps and fades, begin with step; strong::stepTime:: means time without fade +## fadeMode = 2: alternate fades and steps, begin with fade; strong::stepTime:: means time without fade +## fadeMode = 3: alternate steps and fades, begin with step; strong::stepTime:: means sum of step and fade, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +## fadeMode = 4: alternate fades and steps, begin with fade; strong::stepTime:: means sum of fade and step, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +:: +Defaults to 0. + +argument::sine +Determines the crossfade type: sine-based or not. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::sine:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::sine:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::equalPower +Determines if crossfading of equal power type (square root) should be applied. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::equalPower:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::equalPower:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::power +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude. If power and curve are passed, power applies before. A positive Number or a demand rate or other ugen returning positive strong::power:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::curve +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude according to the lincurve mapping. If power and curve are passed, power applies before. A Number or a demand rate or other ugen returning strong::curve:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::curve:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Calculation of curvature is not giving reliable results when strong::width:: and / or strong::dynOutOffset:: are being modulated at the same time. Defaults to 0. + +argument::allowTypeSeq +Enables sequencing of strong::sine::, strong::equalPower::, strong::power:: and strong::curve:: with demand rate ugens and modulating of strong::sine:: and strong::equalPower:: with other ugens. A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0. + +argument::fadeRate +One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. Defaults to \ar. + +argument::maxFadeNum +Integer determining the maximum number of fades, after which strong::doneAction:: applies. A SequenceableCollection causes multichannel expansion. Not modulatable. Defaults to inf. + +argument::maxWidth +An Integer determining the maximum strong::width:: or a SequenceableCollection of such, causing multichannel expansion, strong::width:: goes into PanAz's width arg. strong::maxWidth:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 2. + +argument::width +Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, causing multichannel expansion. Not modulatable in versions earlier than SC 3.9. It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed strong::maxWidth::. Defaults to 2. + +argument::initOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines an initial offset for PanAz's pos arg. This can be useful for a start with full or reduced width. Not modulatable. Defaults to 0. + +argument::maxDynOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines the maximum strong::dynOutOffset:: to be expected. strong::maxDynOutOffset:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 1. + +argument::dynOutOffset +UGen, Integer or Float or a SequenceableCollection of such, causing multichannel expansion. By passing a ugen the movement between buses can be modulated. Note that a ugen's output must not exceed strong::maxDynOutOffset::. Defaults to 0. + +argument::allowFadeEnd +Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion. Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated trigger logic and more running ugens. If set to 0, the behaviour after the end of strong::in:: is undefined. Defaults to 1. + +argument::zeroThr +A Number or a ugen returning strong::zeroThr:: numbers or a SequenceableCollection of such, causing multichannel expansion. Determines if output values below this threshold are replaced by 0. This makes sense if the output signal is used as trigger (e.g. with DXEnvFan). In the case of low power numbers small inaccuracies are amplified, this is avoided with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power. As this requires more ugens running in parallel it is disabled by default = nil. + +argument::doneAction +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the doneAction after strong::maxFadeNum:: is exceeded. Defaults to 0. + +method::kr + + +SECTION::Examples + +anchor::Ex.1:: +code:: +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.reboot; +) +:: + + +subsection::Ex.1: Basic usage: simple crossfade + +code:: +// crossfading between 2 mono sources +// the array of channels to crossfade must be put into a Ref + +( +x = { + DXMix.ar( + Dseq([0, 1], inf), + `[ + Saw.ar(LFDNoise3.kr(0.1).range(40, 90), 0.03), + PinkNoise.ar(0.05) + ], + fadeTime: 3 + ) ! 2 +}.play +) + +x.release + + +// sources can itself be multichannel arrays +// fadeTimes passed as demand rate ugen + +( +x = { + var lfo = LFDNoise3.kr(0.2); + DXMix.ar( + Dseq([0, 1], inf), + `[ + Saw.ar(lfo.range(40, 90) * [1, 1.02], 0.03), + { BPF.ar(PinkNoise.ar(0.05), lfo.range(200, 5000), 0.1) } ! 2 + ], + fadeTime: Dwhite(3, 7) + ) +}.play +) + +x.release + + + +// So far all examples default to width = 2, PanAz's default width. +// It means that at most two channels overlap during crossfade. + +// If higher values of width should be taken, maxWidth must be increased, +// in order to ensure a sufficiently large number of channels used for overlapping internally. +// See Ex.3 for a detailled explanation of the width arg. + +// sliding over a sequence of channel indices + +( +x = { + var lfo = LFDNoise3.kr(0.2); + DXMix.ar( + Dseq([0, 2, 1, 3], inf), + `[ + Saw.ar(lfo.range(40, 70) * [1, 1.02], 0.02), + { BPF.ar(PinkNoise.ar(0.05), lfo.range(200, 5000), 0.1) } ! 2, + Pulse.ar(lfo.range(40, 70) * [1, 1.02], 0.5, 0.02), + { BPF.ar(Dust.ar(100), lfo.range(200, 5000), 0.1) } ! 2 + ], + fadeTime: Dwhite(3, 7), + maxWidth: 5, + width: 4 + ) +}.play +) + +x.release +:: + + +anchor::Ex.2:: +subsection::Ex.2: Basic usage: fades and steps + + +code:: +// in Ex.1 we always used fadeMode's default 0, where only fades are polled +// You might instead want to alternate steps (sections of no fade) with fades: + +// fadeMode = 0: only fadeTimes are used, no steps +// fadeMode = 1: alternate steps and fades, begin with step; stepTime means time without fade +// fadeMode = 2: alternate fades and steps, begin with fade; stepTime means time without fade +// fadeMode = 3: alternate steps and fades, begin with step; stepTime means sum of step and fade, +// thus stepTime must be larger than fadeTime +// fadeMode = 4: alternate fades and steps, begin with fade; stepTime means sum of fade and step, +// thus stepTime must be larger than fadeTime + + +// Check different fadeModes here, different effects with same times: + +// With fadeMode = 2 or 4 we start with a short fade, which gives the impression of a pickup. +// With fadeMode = 3 or 4 the tempo is faster, as fadeTime is subtracted from stepTime. +// With these modes it's the user's responsibility to limit fadeTimes. + + +// NOTE: fadeTimes and stepTimes must be larger than the duration of a control cycle +// with default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. +// If you go below, the step mechanism is messed up you get jumps and clicks. + +// Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, +// which is calculated by stepTime - fadeTime, is larger than this threshold. + + +( +x = { + DXMix.ar( + Dxrand((0..19), inf), + `(Saw.ar((1..10) * 100, 0.1) ++ SinOsc.ar((1..10) * 200, 0, 0.15)), + fadeTime: 0.05, + stepTime: 0.15, + fadeMode: 1 + + // check other fadeModes + + // fadeMode: 2 + // fadeMode: 3 + // fadeMode: 4 + ) + // short fade-in with Function.play to make initial DXMix fade (fadeModes 2 and 4) audible +}.play(fadeTime: 0.005) +) + +x.release + + +// some overtone fun with large width, independent DXMixs for L and R + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + { + DXMix.ar( + Dxrand((0..15), inf), + `(Saw.ar((1..8) * 70 * lfo, 0.05) ++ SinOsc.ar((1..8) * 68.5 * lfo, 0, 0.075)), + fadeTime: 0.02, + stepTime: 0.18, + fadeMode: 1, + width: 7, + maxWidth: 8 + ) + } ! 2 +}.play +) + +x.release + + +// ugen arguments can also be passed to 'in' +// the 'initOutOffset' arg is explained along the next examples + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + { + DXMix.ar( + LFDNoise3.ar(2).range(0, 15), + `(LFTri.ar((1..8) * 70 * lfo, 0, 0.05) ++ SinOsc.ar((1..8) * 68.5 * lfo, 0, 0.075)), + fadeTime: 0.01, + stepTime: 0.15, + fadeMode: 1, + width: 7, + maxWidth: 8, + equalPower: 0, // better here with sines, see curvature options in DXEnvFan help, Ex.1 + initOutOffset: -4 + ) + } ! 2 +}.play +) + +x.release + + + +// stepTime controlled by ugen + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + { + DXMix.ar( + LFDNoise3.ar(2).range(0, 15), + `(LFTri.ar((1..8) * 70 * lfo, 0, 0.05) ++ SinOsc.ar((1..8) * 68.5 * lfo, 0, 0.075)), + fadeTime: 0.01, + stepTime: SinOsc.ar(0.2).range(0.1, 0.5), + fadeMode: 1, + width: 3, + maxWidth: 8, + initOutOffset: -3 + ) + } ! 2 +}.play +) + +x.release +:: + + +anchor::Ex.3:: +subsection::Ex.3: Width and offset arguments for channel span + + +code:: + +// The width parameter determines the number of channels, which are +// maximally affected by the crossfade, it uses the convention of PanAz's width arg. +// The graphics below explain the overlap scheme of DXMix and cousins, +// for DXMix the indices denote the channels to be mixed, +// for DXMixIn the indices denote the buses to be mixed, +// for DXFanOut the buses to which the signal will be spread, +// for DXFan the channels to which the signal will be spread, +// for DXEnvFanOut the buses to which the envelope will be spread. +// for DXEnvFan the channels to which the envelope will be spread. + +// Let's look at a DXMix example with different width values: + + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf), + `(Saw.ar((1..8) * 70 * lfo, 0.075)), + fadeTime: 0.12, + stepTime: 0.38, + fadeMode: 1, + width: 2, + // check other width values below maxWidth + + maxWidth: 8 + ) ! 2 +}.play +) + +x.release + +// Width = 2 means that the crossfade only affects adjacent channels / signals / buses. +// In the graphic the center position of the movement is marked with bold letters, +// a diamond sign denotes, that the center lies in the middle of two channels, +// which are then equally weighted. Squared brackets enclose the active channel numbers. +// So the succession of two rows describes one fade. + +// width = 2: + +:: + +image::attachments/DXMix/sliding_ex_1.png:: + +code:: + +// For an arbitrary integer width n the number of active channels lies between n-1 and n, +// here a scheme of the number of affected channels: + + +width number of channels affected with + center position directly at channel + +2 1 +3 3 +4 3 +5 5 +6 5 +7 7 +8 7 +... + +width number of channels affected with + center position exactly between two channels + +2 2 +3 2 +4 4 +5 4 +6 6 +7 6 +8 8 +... + + +// DXMix and cousins take over the logic of PanAz. However there's a little difference at +// start with width > 2. As we are sliding over a index sequence which has a beginning, +// it seems natural that the start index should be the middle of the span, which is covered according to width. +// So from width > 2 onwards there's a "left side" of the channel span, which hasn't been generated so far, +// thus the full width is not reached before an entrance phase which increases with the width value. + +// width = 3: + +:: + +image::attachments/DXMix/sliding_ex_2.png:: + +code:: +// width = 4: +:: + +image::attachments/DXMix/sliding_ex_3.png:: + +code:: +// If one wants to start width full width there's the possibility to do this by +// passing an initOutOffset argument. + +// Here we start with initOutOffset = 1, fadeMode = 1 (step first), +// index = 4 (5th partial) is the middle of the channel span with most weight, +// which can be clearly perceived. + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf), + `(Saw.ar((1..8) * 70 * lfo, 0.075)), + fadeTime: 0.1, + stepTime: 2, + fadeMode: 1, + width: 3, + maxWidth: 8, + initOutOffset: 1 + ) ! 2 +}.play +) + +x.release + + +// overlap scheme with width = 3 and initOutOffset = 1: +:: + +image::attachments/DXMix/sliding_ex_4.png:: + +code:: +// Here we start with initOutOffset = 0.5, fadeMode = 1 (step first), +// channels with indices 0 and 4 (base tone and 5th partial) are equally weighted. + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf), + `(Saw.ar((1..8) * 70 * lfo, 0.075)), + fadeTime: 0.1, + stepTime: 2, + fadeMode: 1, + width: 3, + maxWidth: 8, + initOutOffset: 0.5 + ) ! 2 +}.play +) + +x.release + + +// overlap scheme with width = 3 and initOutOffset = 0.5: +:: + +image::attachments/DXMix/sliding_ex_5.png:: + + +code:: +// It might also be desirable to start with a fade from silence. +// This can be done with a negative initOutOffset: + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf), + `(Saw.ar((1..8) * 70 * lfo, 0.075)), + fadeTime: 2, + width: 2, + initOutOffset: -1 + ) ! 2 +}.play +) + +x.release + + +// overlap scheme with width = 2 and initOutOffset = -1: +:: + +image::attachments/DXMix/sliding_ex_6.png:: + +code:: + +// width can also be modulated (suited rather for lfos, only enabled from SC 3.9 onwards) + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf), + `(Saw.ar((1..8) * 70 * lfo, 0.05)), + fadeTime: 2, + width: SinOsc.ar(LFDNoise3.ar(1).range(0.2, 10)).range(2, 5), + maxWidth: 5 + ) ! 2 +}.play +) + +x.release + + +// for faster modulations take dynOutOffset, +// maxDynOutOffset must be set properly + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + { + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7], inf), + `(SinOsc.ar((1..8) * 140 * lfo, 0, 0.05)), + fadeTime: 2, + width: 2, + maxDynOutOffset: 2, + dynOutOffset: SinOsc.ar(LFDNoise3.ar(1).range(0.2, 25)).range(0, 2) + ) + } ! 2 +}.play +) + +x.release + + +// You can also control the movement of the channel span entirely by +// passing a ugen to dynOutOffset, therefore set fadeTime to inf. + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + { + DXMix.ar( + Dseq([0, 4, 1, 5, 2, 6, 3, 7, 0], inf), + `(SinOsc.ar((1..8) * 140 * lfo, 0, 0.05)), + fadeTime: inf, + width: 2, + maxDynOutOffset: 7, + dynOutOffset: SinOsc.ar(0.2).range(0, 7) + ) + } ! 2 +}.play +) + +x.release + +:: + +anchor::Ex.4:: +subsection::Ex.4: Switching between PlayBufs + +code:: +// This can go towards granulation + +// load sound file + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + + +// switch between looping PlayBufs + +( +x = { + var sig = { + DXMix.ar( + Dxrand([0, 1, 2], inf), + `(PlayBuf.ar(1, b, BufRateScale.kr(b) * [0.4, 1, 2.2], loop: 1)), + stepTime: 0.2, + fadeTime: 0.01, + fadeMode: 1, + width: 2 + ) } ! 2; + // do a bit correlation + Splay.ar(sig, 0.8) +}.play +) + +x.release +:: + +anchor::Ex.5:: +subsection::Ex.5: Granulation + +code:: +// granulation by fast fading between channels +// here single channels contain PlayBufs with ordered rates + +// load sound file + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + + +// widths (default 2) means overlap, thus grain length = 0.02 +// large-scale polyrhythm by differing rates + +( +x = { + var durs, trig, sig, thr = 0.5; + sig = { |i| + DXMix.ar( + Dseq((49..0), inf), + `(PlayBuf.ar( + 1, + b, + BufRateScale.kr(b) * ({ |j| j / 500 + 0.7 + (i * 0.02) } ! 50), + loop: 1 + )), + fadeTime: 0.01 + ) + } ! 2; + // do a bit correlation + Splay.ar(sig, 0.8) +}.play +) + +x.release + + + +// microsound with synthesized sources +// fadeTime change between very fast and medium length + +// compare version with dynOutOffset + +( +// universal lfo, several instances to be used, thus put into a Function + +l = { LFDNoise3.ar(LFDNoise3.ar(1).exprange(0.1, 30)).range(0.5, 3) }; + +// pool of sources and arguments for channel array + +e = ( + GrayNoise: [0.1], + Dust: [500], + BrownNoise: [0.1], + Pulse: [exprand(50, 500) * l], + SinOsc: [exprand(50, 500) * l], + Saw: [exprand(50, 500) * l] +); + +x = { + var durs, trig, sig, thr = 0.5; + sig = { |i| + DXMix.ar( + Dseq((0..19), inf), + `( + // generate array of oscillators to slide over + { + var sym = e.keys.choose; + sym.asClass.performList(\ar, e[sym]); + } ! 20 + ), + fadeTime: Dstutter( + Diwhite(2, 5), + Dwhite(0.01, 1).linexp(0.01, 1, 0.01, 1) + ), + width: 2, + maxWidth: 2, + // add oscillation between adjacent channels of sequence + // dynOutOffset: SinOsc.ar(LFDNoise3.ar(1).exprange(1, 100)).range(0, 1) + ) * 0.1 + } ! 2; + // do a bit correlation + Splay.ar(sig, 0.8) * 2 +}.play +) + +x.release +:: + +anchor::Ex.6:: +subsection::Ex.6: Multichannel expansion + +code:: +// If a multiple demand rate ugen is implicitely needed, it must be wrapped into a Function + +// Because of the array passed to fadeTime, we need two Dseqs to poll from. +// As only one demand rate ugen is passed as 'in' arg, it must be wrapped into a Function. + +( +x = { + DXMix.ar( + { Dseq([0, 1, 2], inf) }, + // equivalent: + // [Dseq([0, 1, 2], inf), Dseq([0, 1, 2], inf)], + `[ + Saw.ar(LFDNoise3.kr(0.1).range(40, 90), 0.03), + Pulse.ar(LFDNoise3.kr(0.1).range(80, 180), 0.5, 0.03), + PinkNoise.ar(0.05) + ], + fadeTime: [0.03, 3] + ) +}.play +) + +x.release + + +// L and R switching between same sources + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + DXMix.ar( + [Dseq([0, 1, 2], inf), Dseq([2, 3, 1], inf)], + `[ + Saw.ar(lfo.().range(40, 90), 0.03), + BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1), + BPF.ar(Crackle.ar(1.95, 0.5), lfo.().range(200, 5000), 0.1), + Pulse.ar(lfo.().range(40, 90), 0.5, 0.03) + ], + fadeTime: { Dwhite(3, 7) } + ) +}.play +) + +x.release + + +// L and R switching between different sources + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + DXMix.ar( + [Dseq([0, 1], inf), Dseq([1, 0], inf)], + [ + `[ + Saw.ar(lfo.().range(40, 90), 0.03), + BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1) + ], + `[ + Saw.ar(lfo.().range(40, 90), 0.03), + BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1) + ] + ], + fadeTime: { Dwhite(3, 7) } + ) +}.play +) + +x.release + + +// last example, written in a more condensed way + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + DXMix.ar( + [Dseq([0, 1], inf), Dseq([1, 0], inf)], + [ + { Saw.ar(lfo.().range(40, 90), 0.03) } ! 2, + { BPF.ar(PinkNoise.ar(0.05), lfo.().range(200, 5000), 0.1) } ! 2 + ].flop.collect(`_), + fadeTime: { Dwhite(3, 7) } + ) +}.play +) + +x.release + + +// overtone series - L up, R down +// decreasing fundamental + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + DXMix.ar( + [Dseq((0..15), inf), Dseq((15..0), inf)], + `(SinOsc.ar((1..16) * 120 * lfo, 0, 0.05)), + fadeTime: 0.1, + equalPower: 0 + ) +}.play +) + +x.release + + + +// more complicated expansions: +// DXMix produces a nested array of two stereo fades, +// it is mixed to a flat stereo array + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + Mix(DXMix.ar( + [Dseq([0, 1], inf), Dseq([2, 3], inf)], + `[ + Saw.ar(lfo.().range(40, 90) * [1, 3], 0.03), + { BPF.ar(BrownNoise.ar(0.05), lfo.().range(100, 500), 0.3) } ! 2, + SinOsc.ar(lfo.().range(200, 500) * [2, 3], 0, 0.03), + { BPF.ar(Dust.ar(300), lfo.().range(200, 5000), 0.1) } ! 2 + ], + fadeTime: [Dwhite(3, 7), Dwhite(2, 5)] + )) +}.play +) + +x.release + + +// similar situation as above, but the two stereo fades are referring to the same channels +// the result is a kind of accentuation + +( +x = { + var lfo = LFDNoise3.kr(0.2); + Mix(DXMix.ar( + [Dseq([0, 1], inf), Dseq([1, 1, 1, 0], inf)], + `[ + Saw.ar(lfo.range(40, 90) * [1, 3], 0.025), + { BPF.ar(PinkNoise.ar(0.05), lfo.range(500, 5000), 0.1, 5) } ! 2 + ], + fadeTime: [Dwhite(3, 7), 0.1], + // width < 2 produces fade gaps + width: [2, 0.7] + )) +}.play +) + +x.release + + +// interesting multichannel expansions are possible with drate ugens based on nested arrays, +// e.g. coupling of streams + +( +x = { + var lfo = { LFDNoise3.kr(0.2) }; + Mix(DXMix.ar( + Dxrand([[0, 1], [1, 0], [2, 3], [3, 2]], inf), + `[ + Saw.ar(lfo.().range(40, 90) * [1, 3], 0.02), + { BPF.ar(PinkNoise.ar(1), lfo.().range(500, 5000), 0.02, 1) } ! 2, + SinOsc.ar(lfo.().range(400, 900) * [1, 1.2], 0, 0.01), + { BPF.ar(ClipNoise.ar(0.2), lfo.().range(500, 5000), 0.02, 1) } ! 2 + ], + fadeTime: 0.1, + // width < 2 produces fade gaps + width: 1 + )) +}.play +) + +x.release +:: + + +anchor::Ex.7:: +subsection::Ex.7: Stopping and doneAction + +code:: +// The done action is invoked after maxFadeNum. + +( +x = { + var lfo = LFDNoise3.kr(0.2); + DXMix.ar( + Dseq([0, 1], inf), + `[ + Saw.ar(lfo.range(40, 90) * [1, 1.02], 0.03), + { BPF.ar(PinkNoise.ar(0.05), lfo.range(200, 5000), 0.1) } ! 2 + ], + fadeTime: 0.5, + stepTime: 1, + fadeMode: 0, // check with other modes too + maxFadeNum: 5, + doneAction: 2 + ) +}.play +) + +x.release +:: + + + +anchor::Ex.8:: +subsection::Ex.8: Saving CPU + +code:: +// This might be a topic if you're running many fades in parallel and +// fadeTimes are not extremely short (and hence audio rate doesn't make a difference). + +// Here my machine needs ca. 2 % CPU for fadeRate = \kr +// and ca. 6 % CPU for fadeRate = \ar. + +// 10 parallel sequences of overtone fading + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + var sig = DXMix.ar( + { Drand((0..15), inf) }, + `(SinOsc.ar((1..16) * 70 * lfo, 0, 0.2 / (1..16).sqrt)), + fadeTime: 1 / (1..10), + fadeRate: \kr, // check CPU difference to \ar + maxWidth: 4, + width: 3 + ); + Splay.ar(sig) +}.play +) + +x.release + + +// monitoring demand rate ugens needs a quite complicated trigger logic in this context +// per default you can pass finite drate ugens for 'in' - +// observe that layers will stop after different times as fadeTimes are different + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + var sig = DXMix.ar( + { Drand((0..15), 20) }, + `(SinOsc.ar((1..16) * 70 * lfo, 0, 0.2 / (1..16).sqrt)), + fadeTime: 1 / (1..10), + fadeRate: \kr, // also check CPU difference to \ar + maxWidth: 4, + width: 3 + ); + Splay.ar(sig) +}.play +) + +x.release + + +// if you don't need this option you can save a number of ugens with allowFadeEnd = 0, compare + +( +x = { + var lfo = XLine.ar(1, 0.5, 60); + var sig = DXMix.ar( + { Drand((0..15), 20) }, + `(SinOsc.ar((1..16) * 70 * lfo, 0, 0.2 / (1..16).sqrt)), + fadeTime: 1 / (1..10), + fadeRate: \kr, // also check CPU difference to \ar + maxWidth: 4, + width: 3, + allowFadeEnd: 0 + ); + Splay.ar(sig) +}.play +) + +x.release +:: + +note:: +Also see link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2:: and link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for CPU aspects. Note that the use of the options allowTypeSeq and zeroThr also needs more CPU. Rescaling, which is necessary for SC versions before 3.9 with audio rate, is also more CPU-costly. +:: + + diff --git a/HelpSource/Classes/DXMixIn.schelp b/HelpSource/Classes/DXMixIn.schelp new file mode 100644 index 0000000..50a46a0 --- /dev/null +++ b/HelpSource/Classes/DXMixIn.schelp @@ -0,0 +1,219 @@ +CLASS:: DXMixIn +summary:: crossfades between signals from buses according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/DX_suite, Classes/DXMix, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +DXMixIn crossfades between signals from buses according to a sequence of indices, which, together with fadeTimes and stepTimes, can be passed as demand rate ugens. + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the link::Tutorials/DX_suite:: overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::Classes/DXMix#Ex.2#DXMix, Ex.2:: – width and offset arguments in link::Classes/DXMix#Ex.3#DXMix, Ex.3:: – multichannel expansion in link::Classes/DXMix#Ex.6#DXMix, Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#DXEnvFan, Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::Classes/DXMix#Ex.8#DXMix, Ex.8:: and link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2::, link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#DXFan, Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + + +CLASSMETHODS:: + +method::ar + +argument::in +Determines the sequence of signals to be crossfaded. A demand rate or other ugen returning bus indices, a single bus index or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::in:: and the latter contains demand rate ugens, they must all be wrapped into Functions. + +argument::fadeTime +A fade time, a demand rate or other ugens returning fade times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::fadeTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::fadeTime:: depends on strong::fadeMode::. strong::fadeTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::stepTime +A step time, a demand rate or other ugens returning step times or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::stepTime:: and the latter contains demand rate ugens, they must all be wrapped into Functions. The interpretation of strong::stepTime:: depends on strong::fadeMode::. strong::stepTime:: must be larger than the duration of a control cycle. Defaults to 1. + +argument::fadeMode +Integers between 0 and 4 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. +list:: +## fadeMode = 0: only fadeTimes are used, no steps +## fadeMode = 1: alternate steps and fades, begin with step; strong::stepTime:: means time without fade +## fadeMode = 2: alternate fades and steps, begin with fade; strong::stepTime:: means time without fade +## fadeMode = 3: alternate steps and fades, begin with step; strong::stepTime:: means sum of step and fade, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +## fadeMode = 4: alternate fades and steps, begin with fade; strong::stepTime:: means sum of fade and step, thus strong::stepTime:: must be larger than strong::fadeTime::, the difference must be larger than the duration of a control cycle +:: +Defaults to 0. + +argument::sine +Determines the crossfade type: sine-based or not. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::sine:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::sine:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::equalPower +Determines if crossfading of equal power type (square root) should be applied. A Boolean, 0 or 1 or a demand rate or other ugen returning strong::equalPower:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::equalPower:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Modulating this arg is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::power +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude. If power and curve are passed, power applies before. A positive Number or a demand rate or other ugen returning positive strong::power:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Defaults to 1. + +argument::curve +This only comes into play if strong::equalPower:: equals 0, then it's applied to the crossfade amplitude according to the lincurve mapping. If power and curve are passed, power applies before. A Number or a demand rate or other ugen returning strong::curve:: numbers or a SequenceableCollection of such, causing multichannel expansion. If in this case the overall multichannel size is larger than the size of strong::curve:: and the latter contains demand rate ugens, they must all be wrapped into Functions. Sequencing this arg with demand rate ugens is only possible if strong::allowTypeSeq:: equals 1. Calculation of curvature is not giving reliable results when strong::width:: and / or strong::dynOutOffset:: are being modulated at the same time. Defaults to 0. + +argument::allowTypeSeq +Enables sequencing of strong::sine::, strong::equalPower::, strong::power:: and strong::curve:: with demand rate ugens and modulating of strong::sine:: and strong::equalPower:: with other ugens. A Boolean, 0 or 1 or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. As this requires more ugens running in parallel it is disabled by default = 0. + +argument::fadeRate +One of the Symbols \ar and \kr, determining the crossfade rate used by PanAz or a SequenceableCollection of such, causing multichannel expansion. Not modulatable. Defaults to \ar. + +argument::maxFadeNum +Integer determining the maximum number of fades, after which strong::doneAction:: applies. A SequenceableCollection causes multichannel expansion. Not modulatable. Defaults to inf. + +argument::maxWidth +An Integer determining the maximum strong::width:: or a SequenceableCollection of such, causing multichannel expansion, strong::width:: goes into PanAz's width arg. strong::maxWidth:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 2. + +argument::width +Integer, Float, UGen (only from SC 3.9 onwards) or a SequenceableCollection of such, causing multichannel expansion. Not modulatable in versions earlier than SC 3.9. It determines the width according to PanAz's width arg. Note that a ugen's output must not exceed strong::maxWidth::. Defaults to 2. + +argument::initOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines an initial offset for PanAz's pos arg. This can be useful for a start with full or reduced width. Not modulatable. Defaults to 0. + +argument::maxDynOutOffset +An Integer or Float or a SequenceableCollection of such, causing multichannel expansion. Determines the maximum strong::dynOutOffset:: to be expected. strong::maxDynOutOffset:: increases the internally used and potentially needed number of parallel channels. Not modulatable. Defaults to 1. + +argument::dynOutOffset +UGen, Integer or Float or a SequenceableCollection of such, causing multichannel expansion. By passing a ugen the movement between buses can be modulated. Note that a ugen's output must not exceed strong::maxDynOutOffset::. Defaults to 0. + +argument::allowFadeEnd +Integer, Boolean or a SequenceableCollection of such, causing multichannel expansion. Determines if a demand rate input to in with finite length will be monitored, which needs a quite complicated trigger logic and more running ugens. If set to 0, the behaviour after the end of strong::in:: is undefined. Defaults to 1. + +argument::zeroThr +A Number or a ugen returning strong::zeroThr:: numbers or a SequenceableCollection of such, causing multichannel expansion. Determines if output values below this threshold are replaced by 0. This makes sense if the output signal is used as trigger (e.g. with DXEnvFan). In the case of low power numbers small inaccuracies are amplified, this is avoided with an appropriate zeroThr (e.g. = 0.001), as the operation is applied before taking the power. As this requires more ugens running in parallel it is disabled by default = nil. + +argument::doneAction +Integer or a SequenceableCollection of such, causing multichannel expansion. Determines the doneAction after strong::maxFadeNum:: is exceeded. Defaults to 0. + +method::kr + + +SECTION::Examples + +anchor::Ex.1:: +code:: +( +// load with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.reboot; +) +:: + + + +subsection::Ex.1: Crossfaded mixing from buses + +code:: +// play to buses silently + +( +a = Bus.audio(s, 5); + +x = { + Out.ar(a.index, [ + BrownNoise.ar(0.1), + PinkNoise.ar(0.2), + WhiteNoise.ar(0.05), + ClipNoise.ar(0.03), + GrayNoise.ar(0.05) + ]) +}.play +) + +// mix from buses, mind node order + +( +y = { + DXMixIn.ar( + Dxrand((0..4), inf) + a.index, + fadeTime: 0.5, + ) +}.play(addAction: \addToTail) +) + +y.release + + +// cleanup + +( +x.free; +a.free; +) +:: + + +anchor::Ex.2:: +subsection::Ex.2: Multichannel expansion + + +code:: +// play to buses silently + +( +a = Bus.audio(s, 5); +x = { Out.ar(a.index, SinOsc.ar((3..7) * 100, 0, 0.05)) }.play +) + + +// mix the source +// a Drate ugen with arrays causes multichannel expansion +// thus the drate ugen for fadeTime needs to be wrapped into a Function + +( +z = { + DXMixIn.ar( + Drand([[0, 1], [2, 3], [4, 0], [1, 2], [3, 4]], inf) + a.index, + fadeTime: { Dwhite(0.5, 5) } + ) +}.play(addAction: \addToTail) +) + +// stop DXMixIn, source still running + +z.release + + +// get source with other rhythm + +( +z = { + DXMixIn.ar( + Dseq([[0, 1], [2, 3], [4, 0], [1, 2], [3, 4]], inf) + a.index, + fadeTime: [0.05, 2] + ) +}.play(addAction: \addToTail) +) + +z.release + +// cleanup + +( +x.free; +a.free; +) +:: + + diff --git a/HelpSource/Classes/Dictionary.ext.schelp b/HelpSource/Classes/Dictionary.ext.schelp new file mode 100644 index 0000000..9d91b38 --- /dev/null +++ b/HelpSource/Classes/Dictionary.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_maybePutPairs, miSC_getEnvir + + diff --git a/HelpSource/Classes/EZSlider.ext.schelp b/HelpSource/Classes/EZSlider.ext.schelp new file mode 100644 index 0000000..9013a3e --- /dev/null +++ b/HelpSource/Classes/EZSlider.ext.schelp @@ -0,0 +1,7 @@ + +INSTANCEMETHODS:: + +private:: miSC_colorize + +private:: miSC_adaptToControlStep, miSC_mode, miSC_mode_ + diff --git a/HelpSource/Classes/Event.ext.schelp b/HelpSource/Classes/Event.ext.schelp new file mode 100644 index 0000000..0bc00e0 --- /dev/null +++ b/HelpSource/Classes/Event.ext.schelp @@ -0,0 +1,22 @@ + +INSTANCEMETHODS:: + +method:: asESP +Abbreviation for asEventStreamPlayer + + +method::on +See link::Tutorials/Other_event_and_pattern_shortcuts::. Plays an Event. If strong::dur:: isn't specified it is set to inf. + +method::off +See link::Tutorials/Other_event_and_pattern_shortcuts::. Releases the Event's node. + +argument::releaseTime +SimpleNumber for release time. Defaults to nil (default release time of event mechanism). + + +method::eventShortcuts + +Wraps the receiver into a Pcollect with a Function that replaces according to EventShortcuts if it's turned on. This can be useful in cases where a pattern's method embedInStream changes keys of Events before applying the event type function, that employs the normal replacement mechanism of EventShortcuts. Then the mapping can be done inside/before. Normally you wouldn't need to call that method explicitely. See also link::Classes/EventShortcuts::, link::Classes/Event#-eventShortcuts::, link::Classes/SequenceableCollection#-eventShortcuts:: and link::Tutorials/PLx_and_live_coding_with_Strings:: + + diff --git a/HelpSource/Classes/EventShortcuts.schelp b/HelpSource/Classes/EventShortcuts.schelp new file mode 100644 index 0000000..c6cfd31 --- /dev/null +++ b/HelpSource/Classes/EventShortcuts.schelp @@ -0,0 +1,306 @@ +CLASS:: EventShortcuts +summary:: holds default and user-defined dictionaries of shortcuts for events and event patterns +categories::Libraries>miSCellaneous>Event and pattern shortcuts +related:: Overviews/miSCellaneous, Tutorials/PLx_and_live_coding_with_Strings, Tutorials/Other_event_and_pattern_shortcuts + + +DESCRIPTION:: + +Container for dictionaries of shortcuts for the event framework, which can be defined by the user. Shortcuts might be for event keywords or any other (e.g. synth args). At every time one shortcut dictionary is current, but it's only active if EventShortcuts is turned on. Dictionaries are encapsulated and can only be accessed via copies and posting to prevent unintended changes. For event keywords see James Harkins' Practical Guide to Patterns (especially link::Tutorials/A-Practical-Guide/PG_07_Value_Conversions:: and link::Tutorials/A-Practical-Guide/PG_08_Event_Types_and_Parameters::). + + +note:: +Implementation of shortcuts works like this: if you don't turn EventShortcuts on at all, nothing is changed in the event framework – if you turn it on a mapping function is prepended to every event type function, if this has not been done before in this session and the event type function hasn't been newly defined since last prepending – if you turn it off the prepended function is still there, but does no mapping. + +Therfore shortcuts won't work automatically after new definitions of event types. You'd have to turn EventShortcuts on again or apply the method link::Classes/EventShortcuts#*prefixEventTypes::. Quite obviously, switching between different shortcut dictionaries might cause a mess while playing (or pausing and resuming) patterns with these shortcuts. But these are exceptional cases, a typical usage would be defining your personal shortcut dictionary (e.g. in the startup file), turning EventShortcuts on and playing therewith, then maybe turning it off and on again on occasion. + +Some pattern classes (e.g. Ppar) don't work correctly with EventShortcuts, but this can be circumvented by applying shortcuts to source event patterns before, see method link::Classes/Pattern#-eventShortcuts::. See also link::Tutorials/PLx_and_live_coding_with_Strings:: + +:: + +CLASSMETHODS:: + +private::miSC_replaceShortcuts + +method::add + +Adds a new named IdentityDictionary of shortcuts. + +argument::name +Symbol or String. + +argument::dict +IdentityDictionary of abbreviations (keys given as Symbols) and original names (values given as Symbols). + +argument::overwrite +Boolean. Determines if a shortcut dictionary of that name – if existing at all – is overwritten. Defaults to false. + + + +method::addOnBase + +Adds a new named IdentityDictionary of shortcuts based on the copy of an existing one. + +argument::baseName +Symbol or String. Name of the shortcut dictionary to build upon. + +argument::newName +Symbol or String. Name of the new shortcut set. + +argument::dict +IdentityDictionary of new or/and additional abbreviations (keys given as Symbols) and original names (values given as Symbols). + +argument::overwrite +Boolean. Determines if a shortcut dictionary of that name – if existing at all – is overwritten. Defaults to false. +note:: +strong::overwrite:: only determines overwriting of an old dictionary of the same name. It doesn't influence the overwriting in the copy of the base dictionary itself, as exactly this is a main aim of the method. (you might want to replace the association 's'-> 'strum' by 's' -> 'server') +:: + + +method::remove + +Removes a named IdentityDictionary of that name. + +argument::name +Symbol or String. + + +method::removeAll + +Removes all IdentityDictionaries except \default. + + +method::copyDict + +Returns a copy of a shortcut dictionary of that name (if stored). + +argument::name +Symbol or String. + + + +method::copyCurrentDict + +Returns a copy of the current shortcut dictionary of that name. + +argument::name +Symbol or String. + + +method::copyAllDicts + +Returns an IdentityDictionary of copies of all stored shortcut dictionaries. + + + +method::post + +Posts the shortcut dictionary of that name (if stored). + +argument::name +Symbol or String. + + +method::postCurrent + +Posts the current shortcut dictionary. + + + +method::postAll + +Posts all shortcut dictionaries. + + + +method::makeCurrent + +Makes the shortcut dictionary of that name current (if stored). + +argument::name +Symbol or String. + + + +method::on + +Turns on the shortcut mechanism, making it ready for events / patterns to be played. Also invokes link::Classes/EventShortcuts#*prefixEventTypes::. + + +method::off + +Turns the shortcut mechanism off. + + +method::prefixEventTypes + +Puts the remapping function before all event type functions. Therefore a newly defined event type won't work with shortcuts before this has been called ( directly or via link::Classes/EventShortcuts#*on:: ). + + +method::current + +Returns the Symbol of the current shortcut dictionary. + + +method::dictNames + +Returns the Symbols of all shortcut dictionaries. + + +method::state + +Returns the current state (\on or \off). + + + + + +EXAMPLES:: + + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// turn shortcuts on + +EventShortcuts.on + + +// post all, right now only \default exists + +EventShortcuts.postAll + + +// play an Event with midinote 70 + +(m: 70).play + + +// play a Pbind + +( +Pbind( + \m, Pwhite(60, 90, 20) + [0, -7], // midinote + \p, Pwhite(-1.0, 1), // pan + \l, 3, // legato + \s, 0.1, // strum + \d, 0.5 // dur +).play +) + + + +// define new dictionary based on \default with two different shortcuts + +EventShortcuts.addOnBase(\default, \mine, (s: \scale, t: \ctranspose)) + + +// it isn't current yet, make it + +EventShortcuts.makeCurrent(\mine) + + +// play Pbind with new shortcuts, using key/value notation here + +( +p = Pbind(*[ + de: Prand([[0, 1, 26, 27], [-6, 4, 10], [0, 8, 14]], inf), // degree + t: Pwhite(0, 1) + Pwrand([0, -10, 10], [0.9, 0.05, 0.05], 200), // ctranspose + d: 0.2, // dur + s: Scale.chromatic24 // scale +]).play +) + + +// define a SynthDef + +( +SynthDef(\test, { |out = 0, freq = 440, width = 0.5, amp = 0.05, gate = 1, + att = 0.05, rel = 1, pan = 0| + Out.ar(out, Pan2.ar(Pulse.ar(freq, width, amp), pan) * + EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction:2) + ) +}).add +) + + +// you can also define shortcuts for synthdef args + +( +EventShortcuts.addOnBase(\mine, \mine, (w: \width, r: \rel), true); +EventShortcuts.makeCurrent(\mine); +) + + +( +Pbind(*[ + i: \test, // instrument + n: Prand([0, 4, 7], inf), // note + o: Pwhite(5, 6), // octave + dt: Pwhite(0, 20), // detune (in cent) + l: 0.2, // legato + d: 0.2, // dur + w: Pseq((5, 10..40)/100, 4), // width (synth arg) + r: Pseq([0.1, 0.5], inf), // rel (synth arg) +]).play +) + + +// works also with other event patterns: Pmono, PmonoArtic, Pbindef + +( +Pmono(\default, *[ + d: 0.03, // dur + a: 0.3, // amp + dt: Pseq([0, 10], inf), // detune in Hz + p: Pseq((-100, -95..100)/100, 1) // pan +]).play +) + +// further shortcuts for playing events and patterns are collected in "Other event and pattern shortcuts" +// e.g. you can directly play a Pbind derived from an Array: + +( +[ + n: Pshuf((1..12)), // note + d: 0.5, // dur + l: 3, // legato + o: Pwhite(4, 7) // octave +].pp +) + +// also possible with Pbindef, though you shouldn't change current shortcut +// if you still want to refer later on to a Pbindef defined before the change + + +( +Pbindef(\x, *[ + d: Prand([1,1,2]/5, inf), // dur + m: Pwhite(50, 80), // midinote + ct: Prand([[0, 4], [0, 5]], inf) // ctranspose +]).play +) + +Pbindef(\x, \d, Prand([1,1,1,2,3]/7, inf)) + +Pbindef(\x, \ct, [0, 5, 8, 13, 16]) + +Pbindef(\x).stop; + + +// turns off and ensures that default shortcuts are active when EventShortcuts is +// turned on next time in this session + +( +EventShortcuts.off; +EventShortcuts.makeCurrent(\default); +) + +:: + diff --git a/HelpSource/Classes/EventStreamPlayer.ext.schelp b/HelpSource/Classes/EventStreamPlayer.ext.schelp new file mode 100644 index 0000000..d077174 --- /dev/null +++ b/HelpSource/Classes/EventStreamPlayer.ext.schelp @@ -0,0 +1,5 @@ + +INSTANCEMETHODS:: + +method:: asESP +Abbreviation for asEventStreamPlayer diff --git a/HelpSource/Classes/FFT.ext.schelp b/HelpSource/Classes/FFT.ext.schelp new file mode 100644 index 0000000..c526914 --- /dev/null +++ b/HelpSource/Classes/FFT.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_getFFTbufSizes + + diff --git a/HelpSource/Classes/Fb1.schelp b/HelpSource/Classes/Fb1.schelp new file mode 100755 index 0000000..8db9428 --- /dev/null +++ b/HelpSource/Classes/Fb1.schelp @@ -0,0 +1,1652 @@ +CLASS:: Fb1 +summary:: single sample feedback / feedforward pseudo ugen +categories:: Libraries>miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +Fb1 provides an interface for single sample feedback and feedforward at audio and control rate, the defining relation with (formal) access to previous samples is passed as a Function, which might involve additional UGens. Fb1.ar works with arbitrary blockSizes and also allows to refer to samples earlier than one blockSize before. This includes linear filter definitions of arbitrary length with dynamic coefficients as well as all kinds of nonlinear calculations of feedback and feedforward data (FOS and SOS UGens cover the linear case with lengths 1 and 2, LTI the general linear case). + +Fb1 at control rate exists since miSCellaneous v0.22, for compatibility reasons I left the convention that Fb1.new generates an ar UGen, so Fb1.new is now equivalent to Fb1.ar and Fb1.kr is possible in addition, see link::#Ex. 5#Ex.5::. Fb1 is the base of an ordinary differential equation integrator framework for initial value problems, that also came with v0.22, see link::Classes/Fb1_ODE:: for an introduction. + +strong::HISTORY AND CREDITS: :: There have been long discussions on single-sample feedback in SC. The most simple, but CPU-intense strategy is setting the server's blockSize to 1. Julian Rohrhuber gave a number of examples with Dbufrd / Dbufwr. SC's folder 'Examples' contains the files single_sample_feedback.scd and single_sample_feedback_02.scd. Special solutions are also possible with Delay1, Delay2 and other UGens. This particular implementation is based on Nathaniel Virgo's suggestion of iteratively writing to and reading from Buffers of blockSize – big credit for this! See also Nathaniel Virgo's Feedback quark for his feedback classes Fb and FbNode. Thanks also to James Harkins for his remarks on graph order. See link::#Ex. 1a#Ex.1a:: for the basic feedback implementation principle. I implemented the ar feedforward option by temporary buffers for ar writing and kr reading, the feedback / feedforward relation can now be passed via a Function with 'in' and 'out' args. That way the syntax looks very similar to the common notations used for filter descriptions and also applies directly to the multichannel case. Most other options of Fb1 are for special multichannel handling and differentiated lookback definitions, which can help to save a lot of UGens. + + +warning:: +Be careful with amplitudes, feedback can become loud! It is highly recommended to take measures to avoid blowup, e.g. by limiting operators (tanh, softclip, distort) and/or using MasterFX from the JITLibExtensions quark. Also consider that short iteration cycles can produce loud high pitches, wrapping lopass filters is useful! +:: + +note:: +The convenience of direct definition of the feedback / feedforward relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. You might also want to experiment with blockSizes smaller than 64 and larger than 1 (e.g. 8, 16 or 32). Check the strong::graphOrderType:: arg, other values might cause considerable CPU saving and/or shortening of synthdef compile time. +:: + +CLASSMETHODS:: + +private:: checkInits + + +method::new + +Creates a new Fb1 ar object. + + +argument::func +The Function to define the feedback / feedforward relation. The Function should take the two arguments 'in' and 'out', both understood as nested multichannel signals, additionally a block index is passed (link::#Ex. 3e#Ex.3e::). Each 'in' / 'out' item of the arrays represents current or previous samples, for all points in time the samples are passed in specific array shapes, which are determined by the shapes of strong::in:: and strong::outSize::. Allowed are pure signals (size = 0) and nested SequenceableCollections at maximum: e.g. strong::outSize:: can be 0, 3, or [0, 2, 5], accordingly in signals can be of sizes 0, i or [i1, ... , in] with i, ij >= 0. Note that 'in' and 'out' only formally represent ar feedback and feedforward signals, technically kr UGens (BufRd.kr) are passed, the ar signals are reconstructed at the end by reading (arrays of) Buffers. + +The Function should return the multichannel UGen to be referred to with 'out', the shapes of the returned UGens and strong::outSize:: must be the same. Furthermore the meaning of 'in' and 'out' depends on the strong::inDepth:: and strong::outDepth:: arguments. If an Integer is passed to them (default), the indices of 'in' resp. 'out' correspond to the lookback indices: E.g. out[1] refers to the last output sample(s) (of shape strong::outSize::), out[2] to the output sample(s) before the last output sample(s) etc. This is compliant with the convention of writing out[i-1], out[i-2] etc., out[0] refers to out[i-blockSize]. For a multichannel 'in' / 'out' signal, depth can be differentiated, which saves UGens in the case of "gaps" in the recursion: E.g. for a three-channel out signal strong::outDepth:: can look like [3, [7, 18], [2, 5, 6]]. Then out[1] is a three-channel signal, whereby out[1][0] corresponds to out[i-1] of the first, out[1][1] to out[i-18] of the second and out[1][2] to out[i-5] of the third component. If the size of strong::inDepth:: / strong::outDepth:: is smaller than outSize, wrapping is applied. As a result double-bracketing can be used to define specific lookback indices for all components of the multichannel signal: E.g. if strong::outDepth:: equals [[7, 18]] for a three-channel signal then out[0] means the three-channel signal out[i-7] and out[1] means out[i-18]. See link::#Ex. 3a#Ex.3a:: for multichannel feedback / feedforward. + + +argument::in +A single ar input signal or a SequenceableCollection of ar input signals to be referred to with strong::func:: (feedforward data). See link::#Ex. 3a#Ex.3a:: for multichannel feedback / feedforward. + + +argument::outSize +Integer or SequenceableCollection thereof, the size(s) defined by the UGen(s) returned by strong::func::. It's the user's responsibilty to pass the correct size(s)! Defaults to 0. + + +argument::inDepth +Integer or SequenceableCollection of Integers or SequenceableCollections thereof, this determines the behaviour of func (see there). If an Integer is passed, it means the maximum storage size for feedforward data. If a SequenceableCollection is passed, lookback indices for feedforward data can be differentiated, its items can again be Integers or SequenceableCollections (see strong::func::). Usually the inner SequenceableCollections should be ordered, but this is not compulsory. Defaults to 1 (no lookback). See link::#Ex. 3c#Ex.3c::. + + +argument::outDepth +Integer or SequenceableCollection of Integers or SequenceableCollections thereof, this determines the behaviour of func (see there). If an Integer is passed, it means the maximum storage size for feedback data. If a SequenceableCollection is passed, lookback indices for feedback data can be differentiated, its items can again be Integers or SequenceableCollections (see strong::func::). Usually the inner SequenceableCollections should be ordered, but this is not compulsory. Defaults to 2 (look back to last sample at maximum). See link::#Ex. 3c#Ex.3c::. + + +argument::inInit +Number or SequenceableCollection, feedforward init data. If a Number is passed, it means the previous init value for the calculation of the first sample(s), if the size of in is larger than 1, this init value is taken for all components of the multichannel signal. If a SequenceableCollection is passed, this differentiates the init values for a multichannel signal 'in' used by strong::func::. Then the components must be Numbers (again defining one init value) or SequenceableCollections, which define a lookback collection: first Number is the previous value, second the value before and so on. If the size of strong::inInit:: is smaller than the size of strong::in::, wrapping is applied, that way a double-bracket array, e.g. [[3, 0, 1]], defines the same init sequence for all components of a multichannel strong::in::. See link::#Ex. 3b#Ex.3b::. + + + +argument::outInit +Number or SequenceableCollection, feedback init data. If a Number is passed, it means the previous init value for the calculation of the first sample(s), if strong::outSize:: is larger than 1, this init value is taken for all components of the multichannel signal 'out' used by strong::func::. If a SequenceableCollection is passed, this differentiates the init values for this multichannel signal. Then the components must be Numbers (again defining one init value) or SequenceableCollections, which define a lookback collection: first Number is the previous value, second the value before and so on. If the size of strong::outInit:: is smaller than strong::outSize::, wrapping is applied, that way a double-bracket array, e.g. [[3, 0, 1]], defines the same init sequence for all components of the multichannel signal 'out' used by strong::func::. See link::#Ex. 3b#Ex.3b::. + + +argument::blockSize +Integer, this should be the server blockSize. It's the user's responsibility to pass the correct number. However it might be interesting to experiment with other values. Defaults to 64. See link::#Ex. 3d#Ex.3d::. + + +argument::blockFactor +Integer. For a value > 1 this allows for lookback indices larger than strong::blockSize::, up to strong::blockSize:: * strong::blockFactor:: - 1. It's the user's responsibility to pass correct Integers in this case. Defaults to 1. See link::#Ex. 3d#Ex.3d::. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and = 0. Note that 'in' and 'out' only formally represent feedback and feedforward signals, technically kr UGens (BufRd.kr) are passed. + +The Function should return the multichannel UGen to be referred to with 'out', the shapes of the returned UGens and strong::outSize:: must be the same. Furthermore the meaning of 'in' and 'out' depends on the strong::inDepth:: and strong::outDepth:: arguments. If an Integer is passed to them (default), the indices of 'in' resp. 'out' correspond to the lookback indices: E.g. out[1] refers to the last control output sample(s) (of shape strong::outSize::), out[2] to the control output sample(s) before the last control sample(s) etc. This is compliant with the convention of writing out[i-1], out[i-2] etc. For a multichannel 'in' / 'out' signal, depth can be differentiated, which saves UGens in the case of "gaps" in the recursion: E.g. for a three-channel out signal strong::outDepth:: can look like [3, [7, 18], [2, 5, 6]]. Then out[1] is a three-channel signal, whereby out[1][0] corresponds to out[i-1] of the first, out[1][1] to out[i-18] of the second and out[1][2] to out[i-5] of the third component. If the size of strong::inDepth:: / strong::outDepth:: is smaller than outSize, wrapping is applied. As a result double-bracketing can be used to define specific lookback indices for all components of the multichannel signal: E.g. if strong::outDepth:: equals [[7, 18]] for a three-channel signal then out[0] means the three-channel signal out[i-7] and out[1] means out[i-18]. See link::#Ex. 3a#Ex.3a:: for multichannel feedback / feedforward. + + +argument::in +A single kr input signal or a SequenceableCollection of kr input signals to be referred to with strong::func:: (feedforward data). See link::#Ex. 3a#Ex.3a:: for multichannel feedback / feedforward. + + +argument::outSize +Integer or SequenceableCollection thereof, the size(s) defined by the UGen(s) returned by strong::func::. It's the user's responsibilty to pass the correct size(s)! Defaults to 0. + + +argument::inDepth +Integer or SequenceableCollection of Integers or SequenceableCollections thereof, this determines the behaviour of func (see there). If an Integer is passed, it means the maximum storage size for feedforward data. If a SequenceableCollection is passed, lookback indices for feedforward data can be differentiated, its items can again be Integers or SequenceableCollections (see strong::func::). Usually the inner SequenceableCollections should be ordered, but this is not compulsory. Defaults to 1 (no lookback). See link::#Ex. 3c#Ex.3c::. + + +argument::outDepth +Integer or SequenceableCollection of Integers or SequenceableCollections thereof, this determines the behaviour of func (see there). If an Integer is passed, it means the maximum storage size for feedback data. If a SequenceableCollection is passed, lookback indices for feedback data can be differentiated, its items can again be Integers or SequenceableCollections (see strong::func::). Usually the inner SequenceableCollections should be ordered, but this is not compulsory. Defaults to 2 (look back to last control sample at maximum). See link::#Ex. 3c#Ex.3c::. + + +argument::inInit +Number or SequenceableCollection, feedforward init data. If a Number is passed, it means the previous init value for the calculation of the first control sample(s), if the size of in is larger than 1, this init value is taken for all components of the multichannel signal. If a SequenceableCollection is passed, this differentiates the init values for a multichannel signal 'in' used by strong::func::. Then the components must be Numbers (again defining one init value) or SequenceableCollections, which define a lookback collection: first Number is the previous value, second the value before and so on. If the size of strong::inInit:: is smaller than the size of strong::in::, wrapping is applied, that way a double-bracket array, e.g. [[3, 0, 1]], defines the same init sequence for all components of a multichannel strong::in::. See link::#Ex. 3b#Ex.3b::. + + +argument::outInit +Number or SequenceableCollection, feedback init data. If a Number is passed, it means the previous init value for the calculation of the first control sample(s), if strong::outSize:: is larger than 1, this init value is taken for all components of the multichannel signal 'out' used by strong::func::. If a SequenceableCollection is passed, this differentiates the init values for this multichannel signal. Then the components must be Numbers (again defining one init value) or SequenceableCollections, which define a lookback collection: first Number is the previous value, second the value before and so on. If the size of strong::outInit:: is smaller than strong::outSize::, wrapping is applied, that way a double-bracket array, e.g. [[3, 0, 1]], defines the same init sequence for all components of the multichannel signal 'out' used by strong::func::. See link::#Ex. 3b#Ex.3b::. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and 1 blow up ! + // only the next line is limited with softclip + + // in[0][0] is the current stereo signal from the bus + // in[1][0] is the previous + // in[0][1] is the current mono lfo, passed with the 'in' arg + + // func returns a stereo signal, so outSize must be passed 2 + // inDepth [2, 1] because we use inSig[0], inSig[1] and lfo[0] + // outDepth 3 because we use out[2] + // note that it would be cheaper to use out[0] and outDepth: [[2]], + // but a bit more difficult to read + + ((in[0][0] - in[1][0]) % 0.01 * in[0][1]).softclip + }, [inSig, lfo], 2, [2, 1], 3 + ), 15000) * 0.1 +}.play +) + +// start source + +x = { Out.ar(~bus, SinOsc.ar([60, 60.1]) * EnvGate.new) }.play + +// stop source and start new one + +x.release + +x = { Out.ar(~bus, Saw.ar(SinOsc.ar(0.07).linlin(-1, 1, [100, 100.01], 100.2) * EnvGate.new)) }.play + + +x.release + +( +y.free; +~bus.free; +) + +:: + + +anchor::Ex. 2b:: +subsection::Ex. 2b: sin + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// sin can work as a limiter as well as a nonlinear dynamics engine, +// here it causes a wavefolding-like effect + +s.scope + +// start fb fx Synth + +( +~bus = Bus.audio(s, 1); + +y = { + var inSig = In.ar(~bus); + var lfo = SinOsc.ar(0.1, -pi/2).linexp(-1, 1, [5, 10], 100) * 100; + LPF.ar( + Fb1({ |in, out| + // here out[0] refers to out[i-2] because of outDepth: [[2]] + (out[0] * 0.7) + // factors > 1 blow up ! + // here in[0][0] and in[1][0] are current and previous mono inSig, + // but in[0][1] is stereo, so again a stereo signal is returned by func, + // which must be indicated with the outSize arg + ((in[0][0] - in[1][0]) * in[0][1]).sin + }, [inSig, lfo], 2, [2, 1], [[2]] + ) * 0.05, 15000) +}.play +) + +// start source + +x = { Out.ar(~bus, SinOsc.ar(60) * EnvGate.new) }.play; + +x.release; + +// stop source and start new one + +x = { Out.ar(~bus, Saw.ar(SinOsc.ar(0.05).linlin(-1, 1, 100, 100.02) * EnvGate.new)) }.play + +x.release + +( +y.free; +~bus.free; +) +:: + + + +anchor::Ex. 2c:: +subsection::Ex. 2c: * + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// rather irrational concatenation of simple operations +// depth changes cause frequency changes + +s.scope + +// start fb fx Synth + +( +~bus = Bus.audio(s, 1); + +y = { + var inSig = In.ar(~bus); + var lfo = { LFDNoise3.ar(0.07).linexp(-1, 1, 1, 5) } ! 2; + var i = Demand.kr(Dust.kr(0.5), 0, Dxrand((0..2), inf)); + var sig = Fb1({ |in, out| + ( + in[0][1] * ( + in[0][0] * 0.12 + ( + // changes between out[i-23], out[i-41] and out[i-60] cause frequency changes, + // Select depends on a signal from outside, not previous samples as in Ex. 2f + (in[1][0].squared - Select.kr(i, out).squared).sqrt + ) + ) + ).tanh + }, [inSig, lfo], 2, [2, 1], [[23, 41, 60]]) * 0.1; + // add frequency modulation by delay modulation + // lopass filtering with lag + DelayC.ar(sig, 0.2, LFDNoise3.ar(1).range(0.01, 0.1)).lag(0.0005) +}.play +) + +// start source + +x = { Out.ar(~bus, LFTri.ar(LFDNoise0.ar(5).exprange(1, 100)) * EnvGate.new) }.play; + +x.release + +( +y.free; +~bus.free; +) +:: + + + +anchor::Ex. 2d:: +subsection::Ex. 2d: / + + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// With divisions we must avoid division by zero resp. blowup, here it's max in the divisor. +// The example also establishes a cross-feedback of the two channels by using reverse. + +s.scope + +// start fb fx Synth + +( +~bus = Bus.audio(s, 2); + +y = { + var inSig = In.ar(~bus, 2); + var lfo = LFDNoise3.ar(1).linexp(-1, 1, 0.2, 10); + LPF.ar( + Fb1({ |in, out| + (in[1][0] * in[0][1] / max(0.001, (in[1][0] - out[1].reverse).abs)).tanh + }, [inSig, lfo], 2, [2, 1], 2 + ), 15000) * 0.1 +}.play +) + +// start source + +x = { Out.ar(~bus, SinOsc.ar(LFDNoise3.ar(0.1!2).range(100, 101)) * EnvGate.new) }.play + +x.release + +( +y.free; +~bus.free; +) +:: + + +anchor::Ex. 2e:: +subsection::Ex. 2e: ** + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + + +// exponentiation can also be interesting +// here an area of instability is crossed by a stereo lfo + +s.scope + +// start fb fx Synth + +( +~bus = Bus.audio(s, 1); + +y = { + var inSig = In.ar(~bus); + var lfo = { LFDNoise3.ar(0.5).linexp(-1, 1, 0.1, 150) } ! 2; + + Fb1({ |in, out| + in[1][0] * 0.07 + + // out[0] refers to out[i-2] because of outDepth: [[2]] + (2 ** (in[1][0] - out[0] * in[0][1]).abs).tanh + }, [inSig, lfo], 2, [2, 1], [[2]]) * + // avoid bump at start + EnvGen.ar(Env.asr(2)) +}.play +) + + +// start source + +x = { Out.ar(~bus, LFTri.ar(60) * EnvGate.new) }.play; + + +x.release + +( +y.free; +~bus.free; +) +:: + + +anchor::Ex. 2f:: +subsection::Ex. 2f: Conditional feedback + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// defining the next sample depending on some characteristics of the previous one(s) +// This can be done with the if UGen and Select. +// 'if' doesn't support multichannel expansion, so take Select here + +s.scope + +// noisy texture with beeps + +( +x = { + var src = LFDNoise3.ar(1, 0.1); + // ar modulators to be passed (avoid annoying steady tone caused by kr) + var mod1 = LFDNoise3.ar(1).range(0.01, 0.2); + + // already slight difference results in quite strong stereo decorrelation + var mod2 = LFDNoise3.ar(1).range([0.0001, 0.0002], 0.0049); + + Fb1({ |in, out| + // give same names as above for better readability + var src = in[0][0]; + var mod1 = in[0][1]; + var mod2 = in[0][2]; + softclip( + Select.kr( + // as mod2 is stereo we get stereo expansion + // and in turn different selections + + // outDepth = [[1, 6]] + // so out[0] refers to out[i-1], out[1] to out[i-6] + + out[0] % 0.005 < mod2, + [out[1].neg * mod1, out[0] * 0.1] + ) + src + out[0] + ) + // lopass filtering with lag + }, [src, mod1, mod2], 2, 1, [[1, 6]]).lag(0.001) * 0.5 +}.play +) + +x.release +:: + + + +section::Examples 3: Conventions and args + + + + +anchor::Ex. 3a:: +subsection::Ex. 3a: Multichannel feedback / feedforward + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// in and out can be multichannel signals of arbitrary size or collections thereof, +// however arbitrary nesting is not supported, +// outSize arg has to be passed explicitely, +// size of in arg is taken over automatically. + +// also mind the difference between size 0 and 1: +// with outSize of 1 or [0] Fb1 returns an array + +// here out is of size 3, in of sizes [3, 0] + +( +x = { + var inSig = SinOsc.ar(LFDNoise3.ar(0.01 ! 3).range(100, 101)); // 3 channel in signal + var lfo = LFDNoise3.ar(0.1).linexp(-1, 1, 0.2, 10); + var sig; + sig = LPF.ar( + Fb1({ |in, out| + // in[0][0] and in[1][0] represent current and previous 3 channel samples from inSig + // in[0][1] represents current sample from lfo + // rotate causes cross-feedback of 3 channels + // with reverse only first and last would cross + (in[1][0] * in[0][1] / max(0.001, (in[1][0] - out[1].rotate(1)).abs)).tanh + // outSize 3 has to be passed + }, [inSig, lfo], 3, [2, 1], 2 + ), 15000) * 0.1; + Splay.ar(sig) +}.play +) + + +x.release + + +// again out is of size 3, in of sizes [3, 3] + +( +x = { + var inSig = SinOsc.ar(LFDNoise3.ar(0.01 ! 3).range(100, 101)); // 3 channel in signal + var mod = SinOsc.ar([1, 2.001, 3.999] * 120).linexp(-1, 1, 0.2, 10); + var sig; + sig = LPF.ar( + Fb1({ |in, out| + // in[0][0] and in[1][0] represent current and previous 3 channel samples from inSig + // in[0][1] represents current 3 samples from mod + // rotate causes cross-feedback of 3 channels + // with reverse only first and last would cross + (in[1][0] * in[0][1] / max(0.001, (in[1][0] - out[1].rotate(1)).abs)).tanh + // outSize has to be passed + }, [inSig, mod], 3, [2, 1], 2 + ), 15000) * 0.05; + Splay.ar(sig) +}.play +) + +x.release + + +// it's also possible to let func return an array of (multichannel) signals, +// outSize must be set accordingly, here [2, 0], +// whereby the mono within the array is a "helper feedback" + +( +x = { + var inSig = SinOsc.ar(LFDNoise3.ar(1.5 ! 2).exprange(50, 100)); + var lfo = LFDNoise3.ar(5).linexp(-1, 1, 0.5, 100); + var sig; + sig = LPF.ar( + Fb1({ |in, out| + // in[1][0] represents previous 2 channel samples from inSig + // in[0][1] represents current sample from lfo + + // reverse causes cross-feedback of 2 main channels + // main feedback crosses with helper feedback + [ + // for main feedback use helper feedback + (out[1][1] / max(0.001, (in[1][0] - out[1][0].reverse).abs)).tanh, + // for helper feedback use first channel of main feedback + (out[1][0][0] + 0.1 / max(0.01, ((in[0][1].abs)))).tanh + ] + // outSize [2, 0] has to be passed + }, [inSig, lfo], [2, 0], [2, 1], 2 + ), 12000) * 0.2; + // return main feedback + sig[0] +}.play +) + +x.release + + + +// here 2 x stereo, outSize == [2, 2] + +( +x = { + // two stereo sources + var in_1 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(100, 101)); + var in_2 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(150, 151)); + var lfo = LFDNoise3.ar(0.1).linexp(-1, 1, 0.2, 10); + var sig; + sig = LPF.ar( + Fb1({ |in, out| + // rename for better readability + + // previous ins are stereo + var prevIn_1 = in[1][0]; + var prevIn_2 = in[1][1]; + + // mono lfo + var lfo = in[0][2]; + + // out is 2 x 2 (see below) + var prevOut_1 = out[1][0]; // stereo + var prevOut_2 = out[1][1]; // stereo + + // we return an array of two stereo signals + [ + (prevIn_1 * lfo / max(0.001, (prevIn_1 - prevOut_1.reverse).abs)), + (prevIn_2 * lfo / max(0.001, (prevIn_2 - prevOut_2.reverse).abs)) + ].tanh + + // outSize [2, 2] has to be passed + }, [in_1, in_2, lfo], [2, 2], 2, 2 + ), 15000) * 0.05; + sig[0] + sig[1]; // mix together + // sig[0]; + // sig[1]; +}.play +) + +x.release + + +// variant: cross feedback within first stereo out (a) plus +// cross feedback the stereo signals with each other (b) + +// at the end take only first stereo out +// because of (b) the 150 Hz of in_2 are contained in the resulting signal + +( +x = { + var in_1 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(100, 101)); + var in_2 = SinOsc.ar(LFDNoise3.ar(0.1 ! 2).range(150, 151)); + var lfo = LFDNoise3.ar(0.1).linexp(-1, 1, 0.2, 10); + var sig; + sig = LPF.ar( + Fb1({ |in, out| + // rename for better readability + + // previous ins are stereo + var prevIn_1 = in[1][0]; + var prevIn_2 = in[1][1]; + + // mono lfo + var lfo = in[0][2]; + + // out is 2 x 2 (see below) + var prevOut_1 = out[1][0]; // stereo + var prevOut_2 = out[1][1]; // stereo + + // we return an array of two stereo signals + + [ + (prevIn_1 * lfo / max(0.001, (prevIn_1 - prevOut_2.reverse).abs)), + (prevIn_2 * lfo / max(0.001, (prevIn_2 - prevOut_1).abs)) + ].tanh + + // outSize has to be passed + }, [in_1, in_2, lfo], [2, 2], 2, 2 + ), 15000) * 0.05; + sig[0] +}.play +) + +x.release + + +:: + + + + +anchor::Ex. 3b:: +subsection::Ex. 3b: inInit / outInit + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// linear congruential generator + +// this is not a strict linear congruential generator +// as the server doesn't know integers, it's done with floats, +// all is blurred by floating point inaccuracy +// however interesting results can be obtained + +// different start values can produce different orbits + +// WARNING: can produce loud high pitches with certain init values and factors +// as a result of short iteration cycles, take LPF ! + + +// same init value for both channels + +( +x = { + var sig = Fb1({ |in, out| + out[1] * 5.239 % 1 + }, + outSize: 2, + outInit: 1 // [1] is equivalent + ).tanh * 0.2; + LPF.ar(sig, 2000) +}.play +) + +x.release + + +// other iteration sequence by different init value + +( +x = { + var sig = Fb1({ |in, out| + out[1] * 5.239 % 1 + }, + outSize: 2, + outInit: 2 + ).tanh * 0.2; + LPF.ar(sig, 2000) +}.play +) + +x.release + + +// defining different init values per channel + +( +x = { + var sig = Fb1({ |in, out| + out[1] * 5.239 % 1 + }, + outSize: 2, + outInit: [1, 2] + ).tanh * 0.2; + LPF.ar(sig, 2000) +}.play +) + +x.release + + + +// mono, two init values for one channel (previous and previous of previous) +// this needs double brackets for outInit + +( +x = { + var sig = Fb1({ |in, out| + out[1] * 2 + (out[2] * 3) % 1.01 + }, + outSize: 1, + outInit: [[2, 6]], + outDepth: 3 // needed as we look back for 2 values + ).tanh * 0.2; + LPF.ar(sig, 2000) +}.play +) + +x.release + + +// stereo, different arrays of init values per channel + +( +x = { + var sig = Fb1({ |in, out| + out[1] * 2 + (out[2] * 3) % 1.01 + }, + outSize: 2, + outInit: [[3, 1], [2, 5]], + outDepth: 3 + ).tanh * 0.2; + LPF.ar(sig, 2000) +}.play +) + +x.release + + +// inInit values can be defined in the same way as outInit + +// want a trigger at start in connection with Dust + +( +x = { + var trig = Dust.ar(0.3); + var src = SinOsc.ar(1000); + var sig = Fb1({ |in, out| + var tr = in[1][0]; + var mod = in[0][1]; + (out[1] + tr * (mod * 0.02 + 0.999999)) + }, + in: [trig, src], + inDepth: 2, + // here both in buffers get init values, only the first is relevant + inInit: 1, // [1, 0] doesn't make a difference + ).lag(0.005).tanh * 0.5; + sig +}.play +) + +x.release + +// inInit and outInit cannot be differentiated for a multichannel component of a multichannel in / out. +// If you want to do such, you'd have to split the inner +// multichannel component and differentiate the outer one. +:: + + + +anchor::Ex. 3c:: +subsection::Ex. 3c: inDepth / outDepth + + + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// Normally, and like in most previous examples, +// out[j] and in[j] in func refer to samples out[i-j] and in[i-j], +// in[0] to the current input samples. +// The lookback size can be determined by passing Integers to inDepth / outDepth, e.g. +// with inDepth = 2 you can refer to in[0] and in[i-1] +// with outDepth = 3 you can refer to out[i-1] and out[i-2], +// out[0] refers to out[i-blockSize]. + +// When refering not to previous but to earlier samples, +// passing specified inDepth / outDepth indices is saving UGens. + +// Here in[0] refers to in[0], the current sample(s), and +// in[1] refers to in[i-56]. + +( +x = { + var src = SinOsc.ar(500 * LFDNoise3.ar(5)); + var sig = Fb1({ |in, out| + (out[1] / max(0.01, (in[1] - in[0]))).tanh + }, + in: src, + inDepth: [[0, 56]], + outInit: 1 + ) ! 2 * 0.1 ; + sig +}.play +) + +x.release + + +// looking back less far changes the sound colour + +( +x = { + var src = SinOsc.ar(500 * LFDNoise3.ar(5)); + var sig = Fb1({ |in, out| + (out[1] / max(0.01, (in[1] - in[0]))).tanh + }, + in: src, + inDepth: [[0, 29]], + outInit: 1 + ) ! 2 * 0.1; + sig +}.play +) + +x.release + + +// differentiate inDepth per channel + +( +x = { + // stereo in + var src = SinOsc.ar(500 * LFDNoise3.ar(5!2)); + var sig = Fb1({ |in, out| + (out[1] / max(0.01, (in[1] - in[0]))).tanh + }, + outSize: 2, + in: src, + inDepth: [[0, 29], [0, 56]], + outInit: 1 + ) * [0.2, 0.1]; + sig +}.play +) + +x.release + +// inDepth and outDepth cannot be differentiated for a multichannel component of a multichannel in / out. +// If you want to do such, you'd have to split the inner +// multichannel component and differentiate the outer one. +:: + + + + +anchor::Ex. 3d:: +subsection::Ex. 3d: blockSize / blockFactor + + + +code:: + +// Normally Fb1's blockSize should equal the server's current blockSize, +// which can be set as a server option, per default it's 64. + +// If you are using a different blockSize, you can either +// reset it for the examples in this helpfile ... + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// ... or run the examples with passing a different blockSize, e.g. with: + +Fb1(..., blockSize: s.options.blockSize) + + +// You can however try to creativily use a "wrong" blockSize and play with artefacts, +// variant of Ex. 3c + +( +x = { + // stereo in + var src = SinOsc.ar(300 * LFDNoise3.ar(1!2)); + var sig = Fb1({ |in, out| + (out[1] / max(0.01, (in[1] - in[0]))).tanh + }, + outSize: 2, + in: src, + inDepth: [[0, 15], [0, 19]], + outInit: 1, + blockSize: 33 + ) * 0.2; + LPF.ar(sig, 3000) +}.play +) + +x.release + +// variant of Ex. 3c +// suppose a blockSize of 64, to look back to in[i-150] set blockFactor to 3. + +( +x = { + // stereo in + var src = SinOsc.ar(500 * LFDNoise3.ar([0.3, 7])); + var sig = Fb1({ |in, out| + (out[1] / max(0.001, (in[1] - in[0]))).distort + }, + outSize: 2, + in: src, + inDepth: [[0, 150], [0, 29]], + outInit: 1, + blockFactor: 3 + ) * [0.07, 0.15]; + sig +}.play +) + +x.release +:: + + + + +anchor::Ex. 3e:: +subsection::Ex. 3e: func index + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// func can take an index as third arg, it runs from 0 to blockSize - 1 +// this can be used to define the feedback relation depending on it + +// note that inDepth is set to [2, 1] as we look back to inSig[i-1] (in[1][0]), +// but not to lfo[i-1] (in[0][1] == lfo[0]), this saves 128 UGens ! + + +( +x = { + var inSig = SinOsc.ar([50, 50.1]); + var lfo = SinOsc.ar(LFDNoise3.ar(0.1).range(0, 500)).range(0, [100, 105]); + LPF.ar( + Fb1({ |in, out, i| + ( + // establish alternating feedback relations in the synthdef graph + i.odd.if { + in[0][0] * in[0][1] + out[1] + }{ + (in[0][0] - in[1][0]) * out[1] + } + ).tanh + }, [inSig, lfo], 2, [2, 1], 2 + ) * 0.1, 12000) +}.play +) + +x.release + +:: + + + + +anchor::Ex. 4:: +section::Ex. 4: Saving CPU + + +code:: +// check blockSize before (or reset blockSize in examples) + +( +if (s.options.blockSize != 64) { + s.options.blockSize = 64; + s.quit.reboot; +} +) + +// UGens written in func are generated as often as blockSize. +// Therefore, if possible, references to kr UGens outside save resources. +// In addition look for hidden unnecessary operations, which can add hundreds of UGens + + +// 2440 UGens (with blockSize == 64) +// deliberately bad, deterministic lfo is generated blockSize times + + +( +x = { + var sig, src; + src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25); + sig = Fb1({ |in, out| + var a = in[0]; + var b = out[1]; + var lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + softclip((a * a * a) + (a * a) + a + (a * a * b) / max(lfo, a + b)); + }, src, 2) * 0.1; + LPF.ar(sig, 3000) +}.play +) + +x.release + +// 2188 UGens as (blockSize - 1) * 4 = 63 * 4 = 252 UGens are saved + +( +x = { + var sig, src, lfo; + src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25); + lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + sig = Fb1({ |in, out| + var a = in[0]; + var b = out[1]; + softclip((a * a * a) + (a * a) + a + (a * a * b) / max(lfo, a + b)); + }, src, 2) * 0.1; + LPF.ar(sig, 3000) +}.play +) + +x.release + + +// still bad though when looking at the the algebraic identity +// a^3 + a^2 + a + (a * a * b) = ((a + b) * a + a) * a + a +// these are 8 vs 5 operations, so with stereo we can save further +// ((8 - 5) * 2) * 64 = 384 UGens + +// 1804 UGens + +( +x = { + var sig, src, lfo; + src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25); + lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + sig = Fb1({ |in, out| + var a = in[0]; + var b = out[1]; + // with SC's L/R-precendence we can write without brackets + softclip(a + b * a + a * a + a / max(lfo, a + b)); + }, src, 2) * 0.1; + LPF.ar(sig, 3000) +}.play +) + + +x.release + + +// without forcing the topological order of BufRds and BufWrs further UGens are saved, +// this might or might not be the same result, might be distorted in worst case, +// however in all my tests I didn't encounter a single example where it was different + +// 1713 UGens + + +( +x = { + var sig, src, lfo; + src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25); + lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + sig = Fb1({ |in, out| + var a = in[0]; + var b = out[1]; + // with SC's L/R-precendence we can write without brackets + softclip(a + b * a + a * a + a / max(lfo, a + b)); + }, src, 2, graphOrderType: 0) * 0.1; + LPF.ar(sig, 3000) +}.play +) + +x.release + + +// check if it's the same - run silently + +( +x = { + var sig, src, lfo; + src = SinOsc.ar(90 * LFDNoise3.ar(0.3!2).range(0.98, 1.02)) * SinOsc.ar(45.25); + lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + sig = Fb1({ |in, out| + var a = in[0]; + var b = out[1]; + // with SC's L/R-precendence we can write without brackets + softclip(a + b * a + a * a + a / max(lfo, a + b)); + }, src, 2, graphOrderType: 0) - + Fb1({ |in, out| + var a = in[0]; + var b = out[1]; + softclip(a + b * a + a * a + a / max(lfo, a + b)); + }, src, 2) * 0.1; + LPF.ar(sig, 3000) +}.play +) + +x.release + +// see also Ex.5 for saving CPU with kr +:: + + + +anchor::Ex. 5:: +section::Ex. 5: Control rate + + +code:: +// Ex.4 with kr and K2A + +( +x = { + var sig, src, lfo; + src = SinOsc.kr(90 * LFDNoise3.kr(0.3!2).range(0.98, 1.02)) * SinOsc.kr(45.25); + lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + sig = Fb1.kr({ |in, out| + var a = in[0]; + var b = out[1]; + // with SC's L/R-precendence we can write without brackets + softclip(a + b * a + a * a + a / max(lfo, a + b)); + }, src, 2, graphOrderType: 0) * 0.1; + LPF.ar(K2A.ar(sig), 3000) +}.play +) + +x.release + + +// FM with same signal + +( +x = { + var sig, src, lfo; + src = SinOsc.kr(90 * LFDNoise3.kr(0.3!2).range(0.98, 1.02)) * SinOsc.kr(45.25); + lfo = SinOsc.kr(SinOsc.kr(0.1).range(0.03, 1)).range(0.001, 0.01); + sig = Fb1.kr({ |in, out| + var a = in[0]; + var b = out[1]; + // with SC's L/R-precendence we can write without brackets + softclip(a + b * a + a * a + a / max(lfo, a + b)); + }, src, 2, graphOrderType: 0) * 0.1; + SinOsc.ar(2000 * sig, 0, 0.1) +}.play +) + +x.release +:: + diff --git a/HelpSource/Classes/Fb1_Duffing.schelp b/HelpSource/Classes/Fb1_Duffing.schelp new file mode 100755 index 0000000..2c7b6be --- /dev/null +++ b/HelpSource/Classes/Fb1_Duffing.schelp @@ -0,0 +1,320 @@ +CLASS:: Fb1_Duffing +summary:: Duffing pseudo ugen +categories:: Libraries>miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol + + +DESCRIPTION:: + +Fb1_ODE wrapper for the Duffing ODE system with external f: + +y'(t) = w(t) + +w'(t) = f(t) + (gamma * cos(omega * t)) - (delta * w(t)) - (beta * y(t)^3) - (alpha * y(t)) + +coming from the 2nd order equation + +y''(t) + (delta * y'(t)) + (alpha * y(t)) + (beta * y(t)^3) = (gamma * cos(omega * t)) + f(t) + + +It returns a 2-channel signal. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_Duffing ar object. + + +argument::f +Defaults to 0. + + +argument::alpha +Defaults to 0. + + +argument::beta +Defaults to 1. + + +argument::gamma +Defaults to 1. + + +argument::delta +Defaults to 1. + + +argument::omega +Defaults to 1. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 2. Defaults to #[1, 0]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +Fb1_ODE wrapper for the Hopf ODE system with external f: + +v'(t) = (mu - (v(t)^2 + w(t)^2)) * v(t) - (theta * w(t)) + f(t) + +w'(t) = (mu - (v(t)^2 + w(t)^2)) * w(t) + (theta * v(t)) + +It returns a 2-channel signal. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[4]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[5]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: +anchor::[4]:: +anchor::[5]:: + +subsection::References + +numberedList:: +## Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): "Adaptive Frequency Oscillators and Applications". The Open Cybernetics and Systemics Journal, 3, 64-69. https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html +## Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): "Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". Frontiers in Neurorobotics. Published online 2017 Mar 21 https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_Hopf ar object. + + +argument::f +Defaults to 0. + + +argument::mu +Defaults to 1. + + +argument::theta +Defaults to 1. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 2. Defaults to #[1, 1]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withOutScale +Boolean. Determines if the Fb1_ODEdef's default scaling values for integration and differential signals should be applied to the output. Defaults to true. +warning:: strong::withOutScale:: does not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +This is an adaptive variant of Hopf, i.e. it can hold the frequency of an oscillating input f after it vanishes. The model refers to link::#[1]::, see also link::#[2]:: (4.1.) for an enhancement implemented with link::Classes/Fb1_HopfAFDC::. The parameter naming follows the convention of link::#[2]::. + +v'(t) = (mu - (v(t)^2 + w(t)^2)) * v(t) - (theta(t) * w(t)) + f(t) + +w'(t) = (mu - (v(t)^2 + w(t)^2)) * w(t) + (theta(t) * v(t)) + +theta'(t) = -eta * f(t) * w(t) / sqrt(v(t)^2 + w(t)^2) + +It returns a 3-channel signal. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[4]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[5]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: +anchor::[4]:: +anchor::[5]:: + +subsection::References + +numberedList:: +## Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): "Adaptive Frequency Oscillators and Applications". The Open Cybernetics and Systemics Journal, 3, 64-69. https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html +## Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): "Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". Frontiers in Neurorobotics. Published online 2017 Mar 21 https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_HopfA ar object. + + +argument::f +Defaults to 0. + + +argument::mu +Defaults to 1. + + +argument::eta +Defaults to 1. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 3. Defaults to #[1, 1, 1]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withOutScale +Boolean. Determines if the Fb1_ODEdef's default scaling values for integration and differential signals should be applied to the output. Defaults to true. +warning:: strong::withOutScale:: does not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and 0.1).poll; + var src = SinOsc.ar(ratio * 200); + var sig = Fb1_HopfA.ar(src * hold.lag(0.5), 0.15, 2, 800); + sig[0] ! 2 * 0.5 +}.play +) + +x.release + + +// with Saw the result is less exact, sometimes Hopf jumps to higher partials + +( +x = { + var ratio = Demand.ar( + Impulse.ar(3), 0, + Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf) + ).midiratio; + var hold = (MouseX.kr(0, 1) > 0.1).poll; + var src = Saw.ar(ratio * 200); + var sig = Fb1_HopfA.ar(src * hold.lag(0.5), 0.15, 2, 800); + sig[0] ! 2 * 0.5 +}.play +) + +x.release + + +// an inexact adaption can be used though to generate interesting irregular variations +// listen for a while + +( +x = { + var ratio = Demand.ar( + Impulse.ar(3), 0, + Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf) + ).midiratio; + var src = Saw.ar(ratio * 200, 0.3); + var sig = Fb1_HopfA.ar(src, 8, 10.5, 600); + sig[0] ! 2 * 0.3 +}.play +) + +x.release +:: + diff --git a/HelpSource/Classes/Fb1_HopfAFDC.schelp b/HelpSource/Classes/Fb1_HopfAFDC.schelp new file mode 100755 index 0000000..a1ef027 --- /dev/null +++ b/HelpSource/Classes/Fb1_HopfAFDC.schelp @@ -0,0 +1,396 @@ +CLASS:: Fb1_HopfAFDC +summary:: Adaptive Hopf pseudo ugen with fast dynamical coupling +categories:: Libraries>miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +This is an adaptive variant of Hopf, which enhances the adaption mechanism of link::#[1]::, see link::#[2]:: (4.1.) for a description. The parameter naming follows the convention of link::#[2]::. + +v'(t) = (mu - (v(t)^2 + w(t)^2)) * v(t) - (theta(t) * w(t)) + p(t) + +w'(t) = (mu - (v(t)^2 + w(t)^2)) * w(t) + (theta(t) * v(t)) + +tau * beta'(t) = beta0 - beta(t) + (kappa * p(t) * v(t)) + +tau * epsilon'(t) = epsilon0 - epsilon(t) + (kappa * f(t) * p(t)) + +theta'(t) = -eta * p(t) * w(t) / sqrt(v(t)^2 + w(t)^2) + +with + +p(t) = (epsilon(t) * f(t)) - (beta(t) * v(t)) + + +It returns a 5-channel signal. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[4]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[5]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: +anchor::[4]:: +anchor::[5]:: + +subsection::References + +numberedList:: +## Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): "Adaptive Frequency Oscillators and Applications". The Open Cybernetics and Systemics Journal, 3, 64-69. https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html +## Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): "Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". Frontiers in Neurorobotics. Published online 2017 Mar 21 https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_HopfAFDC ar object. + + +argument::f +Defaults to 0. + + +argument::mu +Defaults to 1. + + +argument::eta +Defaults to 1. + + +argument::tau +Defaults to 1. + + +argument::kappa +Defaults to 1. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 5. Defaults to #[1, 1, 0.01, 0.01, 1]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withOutScale +Boolean. Determines if the Fb1_ODEdef's default scaling values for integration and differential signals should be applied to the output. Defaults to true. +warning:: strong::withOutScale:: does not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and 0.1).poll; + var src = SinOsc.ar(ratio * 200); + var sig = Fb1_HopfAFDC.ar(src * hold.lag(0.1), 0.2, 0.6, 1, 50, 150) * + EnvGen.ar(Env.asr(0.05)); + [sig[0] * 0.7, src * 0.1] +}.play +) + +x.release + + +// in contrast to Fb1_HopfA adaption to the Saw works quite well + +( +x = { + var ratio = Demand.ar( + Impulse.ar(3), 0, + Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf) + ).midiratio; + var hold = (MouseX.kr(0, 1) > 0.1).poll; + var src = Saw.ar(ratio * 200); + var sig = Fb1_HopfAFDC.ar(src * hold.lag(0.1), 0.2, 0.6, 1, 50, 150) * + EnvGen.ar(Env.asr(0.05)); + [sig[0] * 0.5, src * 0.04] +}.play +) + +x.release + + +// it works still with faster tempo and bigger jumps +// however big jumps and/or the hold gate make the system instable, +// compose with clip helps + +( +x = { + var ratio = Demand.ar( + Impulse.ar(7), 0, + Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf) + Drand([0, 12, 24], inf) + ).midiratio; + var hold = MouseX.kr(0, 1) > 0.1; + var src = Saw.ar(ratio * 200); + var tMul = 150; + var sig = Fb1_HopfAFDC.ar(src * hold.lag(0.1), 0.2, 0.6, 1, 50, tMul, + compose: { |x| x.clip2(100) } + ) * EnvGen.ar(Env.asr(0.05)); + [sig[0] * 0.5, src * 0.04] +}.play +) + +x.release + + +// confused adaption by feeding with phase modulated signal + +( +x = { + var ratio = Demand.ar( + Impulse.ar(3), 0, + Dseq([0, 2, 4, 5, 7, 9, 11, 12], inf) + ).midiratio; + var src = SinOsc.ar(ratio * 200, SinOsc.ar(200).range(0.2, 1)); + var sig = Fb1_HopfAFDC.ar(src, 1.5, 1, 1, 100, 200) * + EnvGen.ar(Env.asr(0.05)); + sig[0] ! 2 * 0.3 +}.play +) + +x.release +:: + diff --git a/HelpSource/Classes/Fb1_Lorenz.schelp b/HelpSource/Classes/Fb1_Lorenz.schelp new file mode 100755 index 0000000..2167488 --- /dev/null +++ b/HelpSource/Classes/Fb1_Lorenz.schelp @@ -0,0 +1,335 @@ +CLASS:: Fb1_Lorenz +summary:: Lorenz pseudo ugen +categories:: Libraries>miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +Fb1_ODE wrapper for the Lorenz ODE system: + +u'(t) = s * (v(t) - u(t)) + +v'(t) = (u(t) * (r - w(t))) - v(t) + +w'(t) = (u(t) * v(t)) - (b * w(t)) + +It returns a 3-channel signal. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_Lorenz ar object. + + +argument::s +Defaults to 10. + + +argument::r +Defaults to 30. + + +argument::b +Defaults to 2. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 3. Defaults to #[1, 1, 1]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withOutScale +Boolean. Determines if the Fb1_ODEdef's default scaling values for integration and differential signals should be applied to the output. Defaults to true. +warning:: strong::withOutScale:: does not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +Fb1_ODE wrapper for the mass spring damper equation of motion: + +y''(t) * mass = f(t) - (dampen * y'(t)) - (spring * y(t)) + +It returns a 2-channel signal with position and velocity. link::Classes/Fb1_SD:: with unified mass is slightly more efficient than Fb1_MSD and you can always rewrite. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens and further MSD examples. + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_MSD ar object. + + +argument::f +External force. Defaults to 0. + + +argument::mass +Mass. Defaults to 1. + + +argument::spring +Spring stiffness. Defaults to 1. + + +argument::dampen +Dampening factor. Defaults to 0. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 2. Defaults to #[0, 0]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +Pseudo ugen for integrating / audifying ordinary (systems of) differential equations with initial values in realtime, based on the Fb1 single sample feedback class. It makes use of Fb1_ODEdef and Fb1_ODEintdef, containers for ODEs and numerical solution methods, which provide an interface for adding new ODE systems or integration methods interactively. There exists a huge number of ODE models in different areas, e.g. have a look at the SIAM publication Exploring ODEs link::#[1]::, it approaches the topic from an experimental point of view, which is quite related to the demands of practical audification / synthesis / processing. And of course it's fun to define your own ODEs, see this help file and link::Classes/Fb1_ODEdef::. + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::#Examples 5#Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +Fb1_ODE in its plain form (without strong::tMul:: modulation, use of strong::compose:: etc.) produces audio data as a numerical integration of an ODE initial value problem, defined by Fb1_ODEdef and a numerical procedure, defined by Fb1_ODEintdef. This of course supposes well-defined ODE systems and it should be kept in mind that the Fb1_ODE framework doesn't perform any mathematical checks regarding the principal existence and uniqueness of a solution of a given Fb1_ODEdef. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +private:: basicNew + + +method::new + +Creates a new Fb1_ODE ar object. + + +argument::name +The name of the ODE defined and stored via Fb1_ODEdef. Can be one of the predefined ODEs, for which wrappers exist, or a self-defined one. Expects a Symbol. + + +argument::argList +The argList to be passed to the ODE. Can contain ar or kr UGens and SequenceableCollections thereof. + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. If no value is passed, the default value of the referred Fb1_ODEdef is taken, usually 0. + + +argument::y0 +Initial value of the ODE. Expects number or array of correct size, which is determined by the Fb1_ODEdef. If no value is passed, the default value of the referred Fb1_ODEdef is taken. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withOutScale +Boolean. Determines if the Fb1_ODEdef's default scaling values for integration and differential signals should be applied to the output. Defaults to true. +warning:: strong::withOutScale:: does not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +To be used to define ODE systems that can then be audified with Fb1_ODE. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +Fb1_ODE in its plain form (without strong::tMul:: modulation, use of strong::compose:: etc.) produces audio data as a numerical integration of an ODE initial value problem, defined by Fb1_ODEdef and a numerical procedure, defined by Fb1_ODEintdef. This of course supposes well-defined ODE systems and it should be kept in mind that the Fb1_ODE framework doesn't perform any mathematical checks regarding the principal existence and uniqueness of a solution of a given Fb1_ODEdef. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +private:: initClass + + + +method::new + +Creates a new Fb1_ODEdef object. + + +argument::name +The name of the ODE, expects a Symbol. Default Fb1_ODEdefs cannot be overwritten. + + +argument::function +The implementation of the function F which describes the ODE given as Y'(t) = F(t, Y(t)) where Y, F can be a single-valued or vector-valued. It must take time as first and a system state (possibly an array) as second parameter and optional further args that can also be arrays. The system state is expected to have the size of the system (given by strong::y0::'s size), the function's return value must also equal this size. If the system size is greater than 1 the components of the output array should be rather written as Functions, as this optimizes the compile process with symplectic integration procedures, it isn't compulsory though. See examples below and in the source file Fb1_ODEdef.sc. + + +argument::t0 +Number. Default initial time value. + + +argument::y0 +Default initial value of the ODE. Expects number or array and determines the size of the system, strong::function::'s second arg and return value must be of same size. + + +argument::outScale +Number that determines the default multiplier for the integration signal produced by Fb1_ODE when the latter's strong::withOutScale:: flag is set to true (default). Defaults to 1. Especially thought for systems like Lorenz which produce high levels with standard parameters, then it makes sense to set strong::outScale:: to a value smaller than 1. +warning:: strong::outScale:: / strong::diffOutScale:: / strong::withOutScale:: do not implement a general safety net functionality, strong::withOutScale:: 's default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + + +argument::diffOutScale +Number that determines the default multiplier for the differential signal produced by Fb1_ODE when the latter's strong::withOutScale:: flag is set to true (default). Defaults to 1. Especially thought for systems like Lorenz which produce high levels with standard parameters, then it makes sense to set strong::outScale:: to a value smaller than 1. +warning:: strong::outScale:: / strong::diffOutScale:: / strong::withOutScale:: do not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + + + + +method::at + +Returns the Fb1_ODEdef instance of the Symbol strong::key:: if it exists. + +argument::key +Symbol. + + +method::keys + +Returns an array of all keys of currently stored Fb1_ODEdefs. + + +method::postAll + +Posts all keys of currently stored Fb1_ODEdefs. + + +method::remove + +Removes the Fb1_ODEdef of the Symbol strong::key:: from the Dictionary. + +argument::key +Symbol. + + +method::reset + +Removes all Fb1_ODEdefs other than the predefined ones from the Dictionary. + + + + +INSTANCEMETHODS:: + + +private:: initFb1_ODEdef, value, compose, makeFirstOutInit, makeOutInit, getIntSize, dispatchIntFunc + + + +method::next + +Method for language-side integration, gives next value based on previous data. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym', like 'sym2') is highly recommended. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Multi-step procedures are not implemented, remaining: + +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +:: + +argument::t +Previous time, expects Number. + + +argument::y +Previous state, expects Number or Array of system size. + + +argument::dt +Number. Time delta. + + +argument::args +List of additional args to be passed to Fb1_ODEdef's function. + + + +method::nextN + +Method for language-side integration, gives an array of next strong::n:: values (arrays) based on previous data. Last values (arrays) are stored at last position. For intTypes with sizeFactor 2 the differential is included. See Examples. + + +argument::n +Integer. Number of next values (resp. value arrays) to be calculated. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym', like 'sym2') is highly recommended. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Multi-step procedures are not implemented, remaining: + +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +:: + +argument::t +Previous time, expects Number. + + +argument::y +Previous state, expects Number or Array of system size. + + +argument::dt +Number. Time delta. + + +argument::args +List of additional args to be passed to Fb1_ODEdef's function. + + +argument::withTime +Boolean. Determines if integrated time should be included. Defaults to false. + + +argument::includeStart +Boolean. Determines if start value(s) should be included. Defaults to true. + + +method::name +Getter for the Fb1_ODEdef's name. + + +method::function +Getter for the Fb1_ODEdef's function. + + +method::name +Getter for the Fb1_ODEdef's name. + + +method::t0 +Getter for the Fb1_ODEdef's t0. + + +method::y0 +Getter for the Fb1_ODEdef's y0. + + +method::outScale +Getter for the Fb1_ODEdef's outScale. + + +method::diffOutScale +Getter for the Fb1_ODEdef's diffOutScale. + + +method::size +Getter for the Fb1_ODEdef's system size. + + + + + + +section::Examples 1: Defining new ODEs + +code:: +// reboot with reduced blockSize + +( +s = Server.local; +Server.default = s; +s.options.blockSize = 8; +s.reboot; +) +:: + + + +anchor::Ex. 1a:: +subsection::Ex. 1a: Extending the harmonic oscillator + + +code:: +// This seems to be an interesting strategy. +// We can e.g. try to multiply one of its equations with a term near 1, +// so start with rather small k and investigate + +// y'(t) = w(t) +// w'(t) = -y(t) * (1 + (k * w(t))) + + +( +Fb1_ODEdef(\harmonic_ext_1, { |t, y, k| + [ + y[1], + y[0].neg * (1 + (k * y[1])) + ] +}, 0, [0, 1], 1, 1); +) + + +// brassy sound + +( +x = { + var sig = Fb1_ODE.ar(\harmonic_ext_1, + [1], 1500, 0, [0, 1], + ) * 0.1; + sig +}.play +) + +x.release + + +// with oscillating k the system tends to become unstable +// but with softclip per sample it can be kept +// (see chapter 'compose' option in Fb1_ODE help) + +( +x = { + var sig = Fb1_ODE.ar(\harmonic_ext_1, + // k oscillates between 1 and 3 + [SinOsc.ar(50).lincurve(-1, 1, 1, 3, 2)], + 1500, 0, [0, 1], + compose: \softclip + ) * 0.1; + sig +}.play +) + +x.release + + +// an oscillation between 1 and higher values totally changes the spectrum + +( +x = { + var sig = Fb1_ODE.ar(\harmonic_ext_1, + // k oscillates between 1 and 10 + [SinOsc.ar(50).lincurve(-1, 1, 1, 10, 2)], + 1500, 0, [0, 1], + compose: \softclip + ) * 0.1; + sig +}.play +) + +x.release + + +// play with the two states + +( +x = { + var sig = Fb1_ODE.ar(\harmonic_ext_1, + // upper oscillation bound for k oscillates itself between 2 and 15 + [SinOsc.ar(50).lincurve(-1, 1, 1, SinOsc.ar(SinOsc.ar(0.2).exprange(0.2, 15)).range(2, 15), 2)], + 1500, 0, [0, 1], + compose: \softclip + ) * 0.1; + sig +}.play +) + +x.release +:: + + + + +anchor::Ex. 1b:: +subsection::Ex. 1b: Extending exponential decay + + +code:: +// exponential decay is described by the equation +// y'(t) = -y(t) + +// an oscillating decay can e.g. be got by +// y'(t) = -y(t) * sin(t) +// the analytic solution includes a log of the sine, +// so we get more partials + + +( +Fb1_ODEdef(\exp_decay_raw, { |t, y| + y.neg * sin(t) +}, 0, 1, 1, 1); +) + + +( +x = { + var sig = Fb1_ODE.ar(\exp_decay_raw, + tMul: 100 * 2pi, + compose: \softclip + ) ! 2; + Line.kr(dur: 10, doneAction: 2); + sig +}.play +) + +x.release + + +// multiplication with a second sine with multiplied time leads to strange and interesting results + +( +Fb1_ODEdef(\exp_decay_extended, { |t, y, k| + y.neg * (sin(t) * sin(k * t)) +}, 0, 1, 1, 1); +) + + + +// ATTENTION: danger of blowup, can be reduced with softclip composition per sample +// constant values lead to ring modulation-like effects ... + +( +x = { + var sig = Fb1_ODE.ar(\exp_decay_extended, + [2.7], 100 * 2pi, 0, 1, + compose: \softclip + ); + Line.kr(dur: 10, doneAction: 2); + sig ! 2 +}.play +) + +x.release + + +// ... whereas modulations produce more complex changing spectra +( +x = { + var sig = Fb1_ODE.ar(\exp_decay_extended, + [SinOsc.ar(120).range(3, 3.01)], 100 * 2pi, 0, 1, + compose: \softclip + ); + Line.kr(dur: 10, doneAction: 2); + sig ! 2 +}.play +) + +x.release + + +// for decorrelated stereo we can expand to two independent equations +// k should be of size 2 + +( +Fb1_ODEdef(\exp_decay_extended_2, { |t, y, k| + [ + y[0].neg * (sin(t) * sin(k[0] * t)), + y[1].neg * (sin(t) * sin(k[1] * t)) + ] +}, 0, [1, 1], 1, 1); +) + +( +x = { + var sig = Fb1_ODE.ar(\exp_decay_extended_2, + [SinOsc.ar(120).range([3, 3.01], [3.01, 3.02])], 100 * 2pi, 0, [1, 1], + compose: \softclip + ); + Line.kr(dur: 10, doneAction: 2); + sig +}.play +) + +x.release +:: + + + +anchor::Ex. 2:: +section::Ex. 2: Language-side integration + + +code:: +// Possible though not optimized. +// For longer sections it's probably better to employ Fb1 ODE solvers, +// store audio in a buffer and load it into a float array, +// for quick tests it might be useful though. + +// integrate begin of a Lorenz system, last array is last state, so flop for plot + +( +a = Fb1_ODEdef.at(\Lorenz).nextN( + n: 1000, + intType: \sym2, + t: 0, + y: [1, 1, 1], + dt: 1/100, + args: [30, 12, 2] +); + +a.flop.plot +) +:: + + + + diff --git a/HelpSource/Classes/Fb1_ODEintdef.schelp b/HelpSource/Classes/Fb1_ODEintdef.schelp new file mode 100755 index 0000000..3c23144 --- /dev/null +++ b/HelpSource/Classes/Fb1_ODEintdef.schelp @@ -0,0 +1,186 @@ +CLASS:: Fb1_ODEintdef +summary:: container for ordinary differential equation numeric integrators +categories:: Libraries>miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + +For the optional definition of ODE integration procedures that can then be used with Fb1_ODE. This is an advanced feature, the built-in symplectic procedures should suffice for most use cases. See the source code in Fb1_ODEintdef.sc for the way integrators are defined and link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +Fb1_ODE in its plain form (without strong::tMul:: modulation, use of strong::compose:: etc.) produces audio data as a numerical integration of an ODE initial value problem, defined by Fb1_ODEdef and a numerical procedure, defined by Fb1_ODEintdef. This of course supposes well-defined ODE systems and it should be kept in mind that the Fb1_ODE framework doesn't perform any mathematical checks regarding the principal existence and uniqueness of a solution of a given Fb1_ODEdef. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +private:: initClass + + + +method::new + +Creates a new Fb1_ODEintdef object and stores it in a Dictionary for further usage with Fb1_ODE. + + +argument::name +The name of the integration procedure, expects a Symbol. Default Fb1_ODEintdefs cannot be overwritten. + + +argument::function +The implementation of the Function ("stepper") which describes the numeric procedure. It must take the arguments odeDef, t, y, dt and ... args for further ODE args and must return the new integration value(s). For evaluating the ODE function the method Fb1_ODEdef.value is used which performs the evaluation depending on its first argument. + + +argument::stepDepth +Integer. Values greater than one are for multi-step procedures. Defaults to 1. + + +argument::sizeFactor +Integer. 1 means that the procedure buffers only integration values, 2 means that the differential is buffered too. Defaults to 1. + + + + +method::at + +Returns the Fb1_ODEintdef instance of the Symbol strong::key:: if it exists. + +argument::key +Symbol. + + +method::keys + +Returns an array of all keys of currently stored Fb1_ODEintdefs. + + +method::postAll + +Posts all keys of currently stored Fb1_ODEintdefs. + + +method::remove + +Removes the Fb1_ODEintdef of the Symbol strong::key:: from the Dictionary. + +argument::key +Symbol. + + +method::reset + +Removes all Fb1_ODEintdefs other than the predefined ones from the Dictionary. + + + + +INSTANCEMETHODS:: + + +private:: initFb1_ODEintdef + + +method::name + +Getter for the Fb1_ODEintdef's name. + + +method::function + +Getter for the Fb1_ODEintdef's function. + + +method::stepDepth + +Getter for the Fb1_ODEintdef's stepDepth. + + +method::sizeFactor + +Getter for the Fb1_ODEintdef's sizeFactor. + + + + + + +section::Examples + + +code:: +// This shows how the classical 4-step Runge-Kutta is implemented, +// quite straight it follows its mathematical definition. + +// t: old time +// y: old state (array) +// dt: integration step +// size: size of the ODE (not used here, but needs to be there) +// ... args is for further args of the ODE + +// The odeDef argument expects the Fb1_ODEdef object. +// The evaluation of the ODE function is implemented by odeDef::value. +// This method takes a first argument i which determines the kind of evaluation: +// For i == nil it returns the evaluation value(s) as Array, +// for a number it only returns the ith component. +// The distinction is necessary as the symplectic procedures refer to +// the single components of the ODE system. + +// There exist also symplectic Runge-Kutta procedures which I didn't test so far. +// they would probably also need that option. + +Fb1_ODEintdef(\rk4, + { |odeDef, t, y, dt, size ... args| + var k1 = odeDef.(nil, t, y, *args); + var k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + y, *args); + var k3 = odeDef.(nil, dt * 0.5 + t, k2 * dt * 0.5 + y, *args); + var k4 = odeDef.(nil, dt + t, k3 * dt + y, *args); + ((k2 + k3) * 2 + k1 + k4) * dt / 6 + y + }, 1, 1); + + +// The same procedure as '_d' variant which stores the differential +// The argument y is now passed an array of doubled size with the +// last differential values in the second half of it. +// Finally the new differential value is calculated and appended to the integration. + +Fb1_ODEintdef(\rk4_d, + { |odeDef, t, y, dt, size ... args| + var k1, k2, k3, k4, yy, ff, yNew, fNew; + yy = y[0..size-1]; + ff = y[size..2*size-1]; + k1 = ff; + k2 = odeDef.(nil, dt * 0.5 + t, k1 * dt * 0.5 + yy, *args); + k3 = odeDef.(nil, dt * 0.5 + t, k2 * dt * 0.5 + yy, *args); + k4 = odeDef.(nil, dt + t, k3 * dt + yy, *args); + yNew = ((k2 + k3) * 2 + k1 + k4) * dt / 6 + yy; + fNew = odeDef.(nil, t + dt, yNew, *args); + yNew ++ fNew + }, 1, 2); +:: + diff --git a/HelpSource/Classes/Fb1_SD.schelp b/HelpSource/Classes/Fb1_SD.schelp new file mode 100755 index 0000000..43b0173 --- /dev/null +++ b/HelpSource/Classes/Fb1_SD.schelp @@ -0,0 +1,304 @@ +CLASS:: Fb1_SD +summary:: spring damper model pseudo ugen +categories:: Libraries>miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_VanDerPol, Classes/Fb1_Duffing + + +DESCRIPTION:: + + +Fb1_ODE wrapper for the spring damper equation of motion with unit mass: + +y''(t) = f(t) - (dampen * y'(t)) - (spring * y(t)) + +It returns a 2-channel signal with position and velocity. Fb1_SD is slightly more efficient than Fb1_MSD and you can always rewrite. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens and further MSD examples. + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[2]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[3]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: + + +subsection::References + +numberedList:: +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_SD ar object. + + +argument::f +External force. Defaults to 0. + + +argument::spring +Spring stiffness. Defaults to 1. + + +argument::dampen +Dampening factor. Defaults to 0. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 2. Defaults to #[0, 0]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1, Classes/GFIS, Classes/Fb1_ODE, Classes/Fb1_ODEdef, Classes/Fb1_ODEintdef, Classes/Fb1_MSD, Classes/Fb1_SD, Classes/Fb1_Lorenz, Classes/Fb1_Hopf, Classes/Fb1_HopfA, Classes/Fb1_HopfAFDC, Classes/Fb1_Duffing + + +DESCRIPTION:: + +Fb1_ODE wrapper for the Van der Pol ODE system with external f: + +y'(t) = w(t) + +w'(t) = f(t) + (mu * (1 - y(t)^2) * w(t)) - (theta^2 * y(t)) + +coming from the 2nd order equation + +y''(t) = f(t) + (mu * (1 - y(t)^2) * y'(t)) - (theta^2 * y(t)) + + +It returns a 2-channel signal. The parameter naming follows the convention of link::#[2]::. As described in link::#[1]:: and link::#[2]:: adaptive variants can be made in the same way as for Hopf and other oscillators. See link::Classes/Fb1_ODE:: for general information about Fb1 ODE integrator UGens. + + + +strong::HISTORY AND CREDITS: :: Big credit to David Pirrò from IEM Graz for pointing me to the symplectic integration methods, which are essential for audifying ODEs, as they help to ensure numeric stability in the long run (e.g. to avoid drifts of oscillations that are mathematically expected to be regular). See the chapter on integration in his dissertation link::#[4]::, pp 135-146. You might also want check David Pirròs optimized ODE compiler named Henri link::#[5]::. Big credit also to Nathaniel Virgo who brought up the buffering strategy used in Fb1, which is Fb1_ODE's working horse. + + +warning:: +Especially with self-defined ODEs the usage of this class is – inherently – highly experimental. Be careful with amplitudes, as always with feedback it can become loud! Sudden blowups might result form the mathematical characteristics of the ODE systems or they might come from parameter changes on which ODEs can react extremely sensitive to, they can also stem from numerical accumulation effects. It is highly recommended to take precautionary measures, e.g. by limiting/distorting operators (tanh, clip, softclip, distort) with the compose option (See link::Classes/Fb1_ODE#Examples 5#Fb1_ODE Examples 5::) and/or external limiting and/or using MasterFX from the JITLibExtensions quark. +:: + +note:: +The convenience of direct definition of the ODE relation comes with the price of a large number of UGens involved. You might want to allow a higher number of UGens with the server option numWireBufs. For a nice workflow I'd recommended to take reduced blockSizes (e.g. 1, 2, 4, 8, 16) while experimenting as compile time is shorter, but once you have finished the design of a SynthDef it might pay going back to blocksize 32 or 64 for runtime efficiency, especially if many kr UGens are involved. +:: + + +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: +anchor::[4]:: +anchor::[5]:: + +subsection::References + +numberedList:: +## Righetti, Ludovic; Buchli, Jonas; Ijspeert, Auke Jan (2009): "Adaptive Frequency Oscillators and Applications". The Open Cybernetics and Systemics Journal, 3, 64-69. https://www.researchgate.net/publication/41666931_Adaptive_Frequency_Oscillators_and_Applications_Open_Access Summary: https://biorob.epfl.ch/research/research-dynamical/page-36365-en-html +## Nachstedt, Timo; Tetzlaff, Christian; Manoonpong, Poramate (2017): "Fast Dynamical Coupling Enhances Frequency Adaptation of Oscillators for Robotic Locomotion Control". Frontiers in Neurorobotics. Published online 2017 Mar 21 https://www.frontiersin.org/articles/10.3389/fnbot.2017.00014/full +## Trefethen, Lloyd N.; Birkisson Ásgeir; Driscoll, Tobin A. (2017): Exploring ODEs. SIAM - Society for Industrial and Applied Mathematics. Free download from: https://people.maths.ox.ac.uk/trefethen/Exploring.pdf +## Pirrò, David (2017). Composing Interactions. Dissertation. Institute of Electronic Music and Acoustics, University of Music and Performing Arts Graz. Free download from: https://pirro.mur.at/media/pirro_david_composing_interactions_print.pdf +## https://git.iem.at/davidpirro/henri +:: + + +CLASSMETHODS:: + +method::new + +Creates a new Fb1_VanDerPol ar object. + + +argument::f +Defaults to 0. + + +argument::mu +Defaults to 1. + + +argument::theta +Defaults to 1. + + + +argument::tMul +Time multiplier, which determines velocity of proceeding in the dynamic system. The default value 1 means that the step delta of time equals 1 / sample duration. For getting audible oscillations you might, depending on the ODE definition, have to pass much higher values. Can also be a kr / ar UGen and might also be negative. + + +argument::t0 +Initial time. Expects Number. Defaults to 0. + + +argument::y0 +Initial value of the ODE. Expects array of size 2. Defaults to #[1, 1]. + + +argument::intType +Integration type. Expects one of the Symbols, for which procedures are stored with Fb1_ODEintdef. The use of symplectic procedures (with prefix 'sym') is highly recommended. Defaults to \sym2. For more accurate integration you can try symplectic procedures of higher order like \sym4, \sym8 etc. Families of integration procedures: +list:: +## Symplectic: \sym2, \sym2_d, \sym4, \sym4_d, \sym6, \sym6_d, \sym8, \sym8_d, \sym12, \sym12_d, \sym16, \sym16_d, \sym32, \sym32_d, \sym64, \sym64_d +## Euler: \eu, \eu_d, \eum, \eum_d, \eui, \eui_d +## Prediction-Evaluation-Correction: \pec, \pece, \pecec, \pecece +## Runge-Kutta: \rk3, \rk3_d, \rk3h, \rk3h_d, \rk4, \rk4_d +## Adams-Bashforth: \ab2, \ab3, \ab4, \ab5, \ab6 +## Adams-Bashforth-Moulton: \abm21, \abm22, \abm32, \abm33, \abm43, \abm44, \abm54, \abm55, \abm65, \abm66 +:: + + +argument::compose +Operator(s) / Function(s) to be applied to the system value on a per-sample base. This of course blurs the numeric procedure but can be used for containing or in a creative way. Can be an operator Symbol, a Function or an arbitrarily mixed SequenceableCollection thereof. The Functions are in any case expected to take an array (the system state) as first argument. If only one Function is given it must output an array of same (system) size. Within a SequenceableCollection a Function must output a value of size 0. Within a SequenceableCollection an operator Symbol is applied only to the corresponding component. A Function can optionally take a second argument which is for ar UGens passed via strong::composeArIn::. + + +argument::composeArIn +ar UGen or SequenceableCollection thereof or a SequenceableCollection that can contain both. This is the way to use ar UGens within a Function passed to compose. UGens are passed to the Function's second argument. + + +argument::dt0 +First time delta in seconds to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. In case of a multi-step procedure a dt0 value will be derived from the default server's properties (sample duration * strong::tMul::). + + +argument::argList0 +Initial argList value(s) to be used for the language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. If no UGens are passed to strong::argList::, values will be assumed from passed strong::argList:: Numbers. + + +argument::init_intType +Integration type for language-side calculation of first values of a multi-step strong::intType:: procedure. This will mostly be irrelevant as (single-step) symplectic procedures are to be preferred. Defaults to \sym8. + + +argument::withOutScale +Boolean. Determines if the Fb1_ODEdef's default scaling values for integration and differential signals should be applied to the output. Defaults to true. +warning:: strong::withOutScale:: does not implement a general safety net functionality, strong::withOutScale::'s default value true does by no means say that output is limited. The default scaling values of predefined Fb1_ODEdefs are average assumptions and can, under different circumstances, always lead to high out levels. +:: + +argument::withDiffChannels +Boolean. Determines if channel(s) with differential value(s) should be returned. This is only applicable with integration types with a sizeFactor == 2, which means that for every sample the values of the differential are buffered. As by default this is not the case for all predefined numeric procedures, there exist variants with appendix '_d', e.g. \sym2_d. Defaults to false. + + +argument::withTimeChannel +Boolean. Determines if accumulated time is output in an additional channel. +warning:: with constant strong::tMul:: it produces an ascending DC which is not affected by strong::leakDC:: if this is set to true. Might especially be of interest if time is modulated. Defaults to false. +:: + +argument::blockSize +Integer, this should be the server blockSize. If no Integer is passed, the current default server's blockSize is assumed (in contrast to Fb1). So explicitely passing a blockSize should only be necessary in special cases, e.g. when compiling before booting. However for a pleasant workflow for ar usage it's recommended to use Fb1_ODE with a reduced server blockSize in order to reduce SynthDef compile time. + + +argument::graphOrderType +0, 1 or 2. Determines if topological order of generated BufRd and BufWr instances in the SynthDef graph is forced by additional UGens. +list:: +##Type 0: forced graph order is turned off. +##Type 1 (default): graph order is forced by summation and miSCellaneous>Nonlinear +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Fb1 + + +DESCRIPTION:: + + +The GFIS class implements functional iteration synthesis as pseudo ugen loosely based on the description by Agostino Di Scipio ([1], [2]), who used the abbreviation FIS and pointed to its rich potential. Yari Marimoto has written a plugin implementation of the main sine-map iteration model, which is included in the trnsnd quark under the same name. The GFIS pseudo ugen implementation allows settings which go beyond functional iteration in a strict sense. + +Principle idea of synthesis: given a parametrized nonlinear function, time-variance of init values and/or parameter sets with fixed iteration depth n can produce interesting waveforms. Due to the highly nonlinear dynamics involved, a great amount of unpredictability invites to experiment and exploration – depending on the characteristics of the time-varying signal, results span from brittle noisy textures to drones with rich spectral movements. The cited papers mainly describe strict iteration with sine and mention iterated waveshaping, but as the GFIS class implementation just takes an arbitrary Function it's easy to blur the concept, e.g. by altering the Function and/or the parametrization depending on the iteration level and/or applying iteration on multichannel signals, crossing their data etc. Also interesting – and probably not widely explored – is the use of functional iteration as controller / modulator / engine for other synthesis methods. + + +warning:: +Be careful with amplitudes, in general higher numbers of iteration produce signals with more energy and due to the nonlinear dynamics signals can suddenly become loud! Also go sure that your function doesn't allow blowup with iteration (this at least doesn't happen with the standard examples of the sine map model). +:: + +subsection::References + +numberedList:: +## Di Scipio, Agostino (1999). "Synthesis Of Environmental Sound Textures by Iterated Nonlinear Functions" in: Proceedings of the 2nd COST G-6 Workshop on Digital Audio Effects (DAFx99), NTNU, Trondheim, December 9-11, 1999. +## Di Scipio, Agostino (2001). "Iterated Nonlinear Functions as a Sound-Generating Engine" Leonardo, Vol. 34, No. 3 (2001), pp. 249-254, MIT Press. +:: + + +CLASSMETHODS:: + +private:: checkInits + +method::ar + +argument::func +Function used to establish the iteration by applying it strong::n:: times at build time of the synthdef graph. The Function should take two arguments: the signal and an optional index. It should return the signal used for iteration. The signal can be multichannel, then the Function might take that into account and refer to single channels of the signal arg – but the Function might also ignore it and rely on multichannel expansion, see examples. + +Note that UGens written within strong::func:: are instantiated strong::n:: times, this is usually not what you want for iterating the same parametrical function, with determined signals it's a waste of CPU and for random UGens the result is different. For the strict interpretation of FIS define the parameter signal outside and refer to it from inside strong::func::. + + +argument::init +Init value for the iteration, can also be a SequenceableCollection. + +argument::n +Integer, the maximum iteration number, it determines how often the Function is used for building the synthdef graph, hence this value is not modulatable. + + +argument::nOut +Integer or SequenceableCollection of Integers. An Integer determines the iteration level of the returned signal. That way you can define a maximum iteration number strong::n:: and switch between lower ones, however strong::n:: iterations are permanently calculated. In general switching will cause clicks, so this is an option for testing primarily. A SequenceableCollection of level indices will produce a multichannel signal, which in turn allows defining smooth transitions between signals of different iteration levels. + + +argument::leakDC +Boolean. Determines if a LeakDC is applied to the output. If the parameter signal doesn't change (which can e.g. happen with a LFDNoise UGen) the result will in general be a DC offset, hence DC leaking is recommended. Defaults to true. + + +argument::leakCoef +Number, the strong::leakDC:: coefficient. Defaults to 0.995. + +method::kr + + +section::Examples 1: The sine map model + +These examples use an iterated sine map as described by Agostino Di Scipio. For the sine map sin(r * x) values of r varying between 2 and 4 are interesting. Driven by LFNoise parametrizations as in the first examples we get noise textures. + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + + +anchor::Ex. 1a:: +subsection::Ex. 1a: Time-varying the factor r + + + +code:: +( +y = { + var r = LFDNoise3.ar(10).range(3.5, 4); + GFIS.ar({ |x| sin(r * x) }, 0.3, 9) * 0.1 ! 2 +}.play +) + +y.release + + +// this is not "classical" FIS: +// for each iteration a different parametrization is taken ! +// As LFDNoise UGens aren't coupled, pulsations are less unique + +( +y = { + GFIS.ar({ |x| sin(LFDNoise3.ar(10).range(3.5, 4) * x) }, 0.3, 9) * 0.1 ! 2 +}.play +) + +y.release + + + +// less iterations + +( +y = { + var r = LFDNoise3.ar(10).range(3.5, 4); + GFIS.ar({ |x| sin(r * x) }, 0.3, 7) * 0.1 ! 2 +}.play +) + +y.release + + + +// different init value + +( +y = { + var r = LFDNoise3.ar(10).range(3.5, 4); + GFIS.ar({ |x| sin(r * x) }, 0.85, 7) * 0.1 ! 2 +}.play +) + +y.release + + + +// higher iteration gives sections with more high frequencies in the spectrum +// even higher numbers soon lead to (interrupted) white noise + +( +y = { + var r = LFDNoise3.ar(3).range(3.5, 4); + GFIS.ar({ |x| sin(r * x) }, 0.3, 12) * 0.03 ! 2 +}.play +) + +y.release + + +// higher iteration numbers can partially be "equilibrated" with lower r +// this leads to different sounds, here a more "airy" noise + +( +y = { + var r = LFDNoise3.ar(7).range(2.9, 3.1); + GFIS.ar({ |x| sin(r * x) }, 0.3, 15) * 0.1 ! 2 +}.play +) + +y.release + + +// granular-like noise burst textures + +( +y = { + var r = LFDNoise3.ar(50).range(2.5, 3); + GFIS.ar({ |x| sin(r * x) }, 0.3, 15) * 0.1 ! 2 +}.play +) + +y.release +:: + + +anchor::Ex. 1b:: +subsection::Ex. 1b: Time-varying init values + + +code:: +// mono + +( +y = { + var i = LFDNoise3.ar(7).range(0.2, 0.9); + GFIS.ar({ |x| sin(3.2 * x) }, i, 10) * 0.1 ! 2 +}.play +) + +y.release + + +// stereo init is propagated to a stereo signal + +( +y = { + var i = LFDNoise3.ar(7).range(0.2, 0.9) * [1, 1.01]; + GFIS.ar({ |x| sin(3.2 * x) }, i, 10) * 0.1 +}.play +) + +y.release + +:: + + + + +anchor::Ex. 1c:: +subsection::Ex. 1c: Time-varying init values and factor r + +code:: +( +y = { + var i = LFDNoise3.ar(7).range(0.2, 0.9) * [1, 1.01]; + var r = LFDNoise3.ar(2).range(3.2, 3.6) * [1, 1.01]; + GFIS.ar({ |x| sin(r * x) }, i, 9) * 0.1 +}.play +) + +y.release +:: + + +anchor::Ex. 1d:: +subsection::Ex. 1d: Producing pitch by periodically oscillating parameters + +code:: +// variants of phase glitter +// note that here again the "lazy" FIS with different oscillators per iteration is used + +( +y = { + var osc = SinOsc.ar(30); + GFIS.ar({ |x| sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) }, [0.5, 0.505], 9) * 0.1 +}.play +) + +y.release + +( +y = { + var osc = SinOsc.ar([30, 30.5]); + GFIS.ar({ |x| sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) }, 0.5, 9) * 0.1 +}.play +) + +y.release + + +( +y = { + var osc = SinOsc.ar([30, 30.5]); + GFIS.ar({ |x| sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) }, [0.5, 0.505], 9) * 0.1 +}.play +) + +y.release + + +// harmonics as different oscillation frequencies per iteration + +( +y = { + var oscMod = SinOsc.ar(0.1).range(30.01, 30.3); + GFIS.ar({ |x, i| + sin((SinOsc.ar([30, oscMod] * (i+1)) + LFDNoise3.ar(0.15)).linlin(-2, 2, 3, 4) * x) + }, [0.5, 0.502], 7) * 0.1 +}.play +) + +y.release + + + +// Pulse as oscillator + +( +y = { + var factors = Demand.ar( + TDuty.ar(Dxrand([4, 5, 7], inf)), + 0, + Dseq([Dseq([1.3, 1.4], 2), 0.5], inf) + ).lag(0.7); + var osc = Pulse.ar([70, 70 * factors]).lag(0.001); + LPF.ar( + GFIS.ar({ |x| + sin((osc + LFDNoise3.ar(0.15)).linlin(-2, 2, 3.2, 4) * x) + }, [0.5, 0.505], 9) * 0.1, + 9000 + ) +}.play +) + + +y.release + +:: + + +anchor::Ex. 2:: +section::Examples 2: The waveshaping model - iteration via buffered data + +code:: +// a Buffer can be filled with an arbitrary mathematical function or audio data + +// load audio + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + + +// load to array + +b.loadToFloatArray(action: { |array| a = array; "done".postln }); + + +// take short snippet, normalize between 0 and 1 +// that's most practical when we map to buffer index later on + +// the sound of the snippet is quite irrelevant +// more oscillations in general produce more noise with iteration +// start trying with sine-like forms + +d = a[3150..3300].normalize; + +d.plot; + + +// fill new buffer for iteration + +c = Buffer.loadCollection(s, d) +:: + + + + +anchor::Ex. 2a:: +subsection::Ex. 2a: Time-varying init values + +code:: +// result of BufRd is used as index for the next BufRd +// needs Buffer c prepared above + +( +y = { + GFIS.ar( + { |x| BufRd.ar(1, c, c.numFrames * x) }, + (LFDNoise3.ar(3) * [1, 1.1]).range(0.5, 0.51), 7 + ) * 0.2 +}.play +) + +y.release +:: + + +anchor::Ex. 2b:: +subsection::Ex. 2b: Time-varying index deviation + + +code:: +// needs Buffer c prepared above + +( +y = { + var add = LFDNoise3.ar(0.3) * [0.05, 0.0505]; + GFIS.ar( + { |x| BufRd.ar(1, c, c.numFrames * (x + add)) }, + 0.5, 7 + ) * 0.2 +}.play +) + +y.release +:: + + + +anchor::Ex. 2c:: +subsection::Ex. 2c: Time-varying init values and index deviation + + +code:: +// needs Buffer c prepared above + +( +y = { + var add = LFDNoise3.ar(0.3) * [0.05, 0.0505]; + GFIS.ar( + { |x| BufRd.ar(1, c, c.numFrames * (x + add)) }, + (LFDNoise3.ar(0.3) * [1, 1.01]).range(0.5, 0.505), 7 + ) * 0.2 +}.play +) + +y.release +:: + + +anchor::Ex. 3:: +section::Examples 3: GFIS as controller / modulator / engine for other synthesis + +This can transfer the instable characteristics to other sound worlds. + + +anchor::Ex. 3a:: +subsection::Ex. 3a: FM + + + +code:: +( +y = { + var mod = GFIS.ar({ |x| sin(LFDNoise3.ar(1).range(2.9, 4) * x) }, 0.3, 7); + SinOsc.ar(mod * [50, 51] * 70 + 300) * LFDNoise3.ar(2).range(0.2, 0.05) +}.play +) + +y.release +:: + + + +anchor::Ex. 3b:: +subsection::Ex. 3b: Buffer modulation phase controlled by GFIS + + +code:: +p = Platform.resourceDir +/+ "sounds/a11wlk01.wav"; +b = Buffer.read(s, p); + +( +y = { + var pos = 0.5; // other pos offset will give totally different sounds + var osc = GFIS.ar({ |x| sin(LFDNoise3.ar(10).range(3.2, 4) * x) }, 0.3, 6) * 0.1; + // GFIS involves a LeakDC, but not BufRd + LeakDC.ar(BufRd.ar(1, b, b.numFrames * (osc * [0.0120, 0.0125] * 5 + pos), interpolation: 4)) * 0.1 +}.play +) + +y.release +:: + + +anchor::Ex. 3c:: +subsection::Ex. 3c: Iterated GFIS + + +code:: +// augmentation of nonlinearity: +// GFIS itself used as time-varying control of another GFIS + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + +// load to array and fill new buffer for iteration + +b.loadToFloatArray(action: { |array| a = array; "done".postln }); + +d = a[3150..3300].normalize; + +c = Buffer.loadCollection(s, d); + + +( +y = { + var r = LFDNoise3.ar(3).range(2.7, 3.4); + var add = GFIS.ar({ |x| sin(r * x) }, 0.5, 3) * [0.05, 0.055]; + GFIS.ar( + { |x| BufRd.ar(1, c, c.numFrames * (x + add)) }, + 0.5, 7 + ) * 0.2 +}.play +) + +y.release +:: + + +anchor::Ex. 4:: +section::Ex. 4: The nOut arg + + + +code:: +// nOut allows for switching between iteration levels up to maximum n + +( +y = { + |nOut = 10| + GFIS.ar({ |x| sin(LFDNoise1.ar(20).range(3, 3.5) * x) }, [0.2, 0.3], 10, nOut) * 0.1 +}.play +) + + +y.set(\nOut, 9) + +y.set(\nOut, 8) + +y.release + + +// it can be passed an array of levels, +// the resulting multichannel signal can e.g. be used for crossfaded switching with DXMix + +// switch between 3 mono signals and double them + +( +y = { + var src = GFIS.ar({ |x| sin(LFDNoise3.ar(30).range(3, 4) * x) }, 0.2, 9, [5, 7, 9]) * 0.1; + DXMix.ar(Dseq([0, 1, 2], inf), `src, fadeTime: 0.01, stepTime: 0.02, fadeMode: 1) ! 2 +}.play +) + +y.release; + +// switch between 3 stereo signals + +( +y = { + var src = GFIS.ar({ |x| sin(LFDNoise3.ar(30).range(3, 4) * x) }, [0.2, 0.21], 9, [5, 7, 9]) * 0.1; + DXMix.ar(Dseq([0, 1, 2], inf), `src, fadeTime: 0.01, stepTime: 0.02, fadeMode: 1) +}.play +) + +y.release; +:: + + + +anchor::Ex. 5:: +section::Ex. 5: Comparison FIS / GFIS + +
code:: +// FIS is contained in the trnsnd quark +// first example of its helpfile + +{ FIS.ar(LinExp.ar(LFTri.ar(0.1), -1, 1, 1, 4), LFNoise2.ar(300).range(0, 1), 3, 0.1) }.play; + +// the same with GFIS requires definition of varying params outside func +
( +y = { + var r = LinExp.ar(LFTri.ar(0.1), -1, 1, 1, 4); + var i = LFNoise2.ar(300).range(0, 1); + GFIS.ar({ |x| sin(r * x) }, i, 3, 3, false) * 0.1 +}.play +) + +y.release + +// proof of concept, difference is silent as it should + +( +z = { + var r = LinExp.ar(LFTri.ar(0.1), -1, 1, 1, 4); + var i = LFNoise2.ar(300).range(0, 1); + GFIS.ar({ |x| sin(r * x) }, i, 3, 3, false) * 0.1 - FIS.ar(r, i, 3, 0.1) +}.play +) + +z.release +:: + + diff --git a/HelpSource/Classes/HS.schelp b/HelpSource/Classes/HS.schelp new file mode 100644 index 0000000..6cb7c85 --- /dev/null +++ b/HelpSource/Classes/HS.schelp @@ -0,0 +1,248 @@ +CLASS:: HS +summary:: object for use of synth values in the language by event patterns +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/PHS, Classes/PHSuse, Classes/PHSplayer, Classes/PHSusePlayer + + +DESCRIPTION:: + + +To be used in connection with link::Classes/PHS:: / link::Classes/PHSuse:: to play event patterns using synth values. Holds a singular synth definition, keeps track of OSC traffic when PHS / PHSuse are played. For using several help synths in parallel or setting controllers of a singular help synth see link::Classes/HSpar:: and related. + + +CLASSMETHODS:: + +method::new + +Creates a new HS object. + +argument::server +Must be running server. + +argument::ugenFunc +Function that defines the synth. + +argument::demandLatency +Latency of help synth in seconds. Default value 0.15. + +argument::respondLatency +Time in seconds, given to the response to be received by the client on time. +Default value 0.15. + +argument::postOSC +Boolean for posting of (server to client) OSC messages. Defaults to false. + +argument::granularity +Time grains per second, quantization for bookkeeping. Defaults to 200. + +argument::inputCheck +Boolean for checking input data. Defaults to true. + + + +discussion:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +// make a new HS +// This compiles the SynthDef and prepares the HS to be played with a PHS, +// no Synth object is yet instantiated. + +h = HS(s, { LFDNoise3.kr(0.7, 15, 75) }); + +:: + +A PHS, like a Pbind, defines event stream behaviour, only durations are given separately. +Here values are demanded just by one stream with constant duration, +but more than one duration pattern per HS and more than one Pbind per duration pattern +may be defined - see the link::Classes/PHS:: help file for examples. + +The play method of a PHS creates a PHSplayer which plays a synth from HS's synth definition, +synth values are accessible within the PHS definition by the variable code::~val::, e.g. by code::Pkey(\val)::. +If HS's synthdef has no args, this must be specified in the PHS by code::nil:: or code::[]::. + +code:: + +p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) ]).play; + +// also: +// p = PHS(h, [], 0.15, [ \midinote, Pfunc { |e| e.use { ~val } } ]).play; + +// stop allows resuming, cleanup with free or Cmd-. + +p.stop; // HS synth still playing + +p.play; // resume the PHSplayer + +p.stop(true); // HS synth also paused + +p.play; // resume the PHSplayer together with HS synth + +p.free; // also stop HS synth and cleanup - PHSplayer and HS object are freed + +:: + +INSTANCEMETHODS:: + +method::demandLatency +Set or get latency of help synth in seconds. Defaults to 0.15. + +method::respondLatency +Set or get time (in seconds) given to the response to be received by the client on time. Defaults to 0.15. + +method::postOSC +Set or get the flag that defines whether OSC messages should be posted or not. Boolean. Defaults to false. + +method::granularity +Set or get the (Integer) number of time grains per second, denoting the quantization for bookkeeping. Defaults to 200. + +method::inputCheck +Set or get the flag that defines whether input data should be checked. Boolean. Defaults to true. + + +method::listen + +Make HS ready to poll values from a synth, demanded by possibly more than one stream. +Therefore strong::num:: trigger synths are run, ready to receive triggers for sending help synth values back to client, +but a synth from HS's ugenFunc definition is not yet playing after that. +If PHS / PHSuse are played there is no need to call strong::listen:: explicitely. + +argument::num +Integer. Number of trigger synths. + +argument::latency +Float. Latency in seconds. + + + +method::play + +Play a synth derived from HS's ugenFunc definition. HS must already be listening. +If PHS / PHSuse are played there is no need to call strong::play:: explicitely. + +argument::args +Synth args. + +argument::latency +Float. Latency in seconds. + +method::clearBookkeeping +Cleanup OSC bookkeeping. + +method::stop +Free the playing help synth and cleanup OSC bookkeeping. + +method::sleep +Free the listening trigger synths. + +method::busFree +Deallocate the bus. + +method::free +Free all related PHSplayers / PHSusePlayers, then strong::stop::, strong::sleep:: and strong::busFree::. + +Note:: strong::stop:: and strong::free:: will normally be called by the respective player methods, see link::Classes/PHSplayer::. +:: + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// define a tendency for chord density + +h = HS(s, { LFDNoise3.kr(0.5, 4, 5) }); + + +// language operations used for building chords from synth values + +( +p = PHS(h, [], 0.18, + [\midinote, Pkey(\val).collect {|x| + Array.series(x.round, 60 - (x * 1.2), 5) + Array.rand(x.round, -0.8, 0.8) }, + \legato, 0.6, + \amp, 0.05] +).play; +) + +// cleanup (freeing buses and nodes) by pressing Cmd-. or explicitely + +p.free; + + +///////////////////////////////////////////////////////////////////// + +// example with other than default instrument +// define synth to move between two sounds + +( +SynthDef(\simpleMorph, {|out = 0, freq = 440, amp = 0.1, morphQ = 0| + var src, normalMorphQ = morphQ.mod(1); + src = Saw.ar(freq, mul: amp) * (1 - normalMorphQ) + (SinOsc.ar(freq, mul: amp) * normalMorphQ); + Out.ar(out, src ! 2 * EnvGen.ar(Env.perc, doneAction: 2)); +}).add; +) + +// HelpSynth definition, values between 0 and 1 +// Clock and quant for syncing + +( +h = HS(s, { LFTri.kr(0.5, mul: 0.5, add: 0.5) }); + +c = TempoClock.new; +q = 0.2; +) + +// help synth values for pitch and synth arg \morphQ + +( +p = PHS(h, [], 0.2, + [\instrument, \simpleMorph, + \midinote, Pkey(\val) * 30 + 60 + [0, 9] + Pxrand([0, 1.5, -1.5], inf), + \amp, 0.07, + \morphQ, Pkey(\val) ] +).play(c,q); +) + + +// sync it with a normal pbind (EventStreamPlayer) with default instrument +// no use of HS / PHS + +( +r = Pbind( + \dur, 0.2, + \midinote, Pxrand([58, 60, 61, 63, 64, 67, 69, 70], inf) + + [-7, 0, 5, 9] + Pseq([0.2, -0.2],inf), + \amp, 0.03 +).play(c, quant: q); +) + +// pause and stop are synonym + +p.pause; + + +// resume p in sync + +p.play(c, q); + + +// stop and free + +( +r.stop; +p.free; +) + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/HSpar.schelp b/HelpSource/Classes/HSpar.schelp new file mode 100644 index 0000000..89bdce8 --- /dev/null +++ b/HelpSource/Classes/HSpar.schelp @@ -0,0 +1,97 @@ +CLASS:: HSpar +summary:: object for use of synth values in the language by event patterns +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/PHSpar, Classes/PHSparUse, Classes/PHSparPlayer, Classes/PHSusePlayer + +DESCRIPTION:: +To be used in connection with link::Classes/PHSpar:: / link::Classes/PHSparUse:: to play event patterns using synth values. Holds synth definitions, keeps track of OSC traffic when PHSpar / PHSparUse are played. For using a singular help synth see link::Classes/HS:: and related. + +CLASSMETHODS:: + +method::new + +Creates a new HSpar object. + +argument::server +Must be running server. + +argument::ugenFuncs +Collection of functions that define the synths. + +argument::demandLatency +Latency of help synths in seconds. Default value 0.15. + +argument::respondLatency +Time in seconds, given to the response to be received by the client on time. Default value 0.15. + +argument::postOSC +Boolean for posting of (server to client) OSC messages. Defaults to false. + +argument::granularity +Time grains per second, quantization for bookkeeping. Defaults to 200. + +argument::inputCheck +Boolean for checking input data. Defaults to true. + + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +// define a HSpar with two help synth definitions + +( +h = HSpar(s, [ { |freq = 1, dev = 10, center = 70| + LFDNoise3.kr(freq, dev, center) }, + { |freq = 1, dev = 5, center = 70, addFreq = 0.1, addDev = 5| + LFTri.kr(freq, 0, dev, center) + SinOsc.kr(addFreq, 0, addDev) } + ]); +) + +// define a PHSpar to switch between these two + +( +p = PHSpar(h, + Pwhite(2.5, 3), // switch duration + Pseq([0,1],inf), // switch indices + // helpSynthArgs: always default values for help synth #0, always set help synth #1 + [nil, [\freq, 1.2, \center, Pwhite(60, 80)] ], + // pbindArgs: different from PHS, they have to be given as collection; ~val refers to current switch + [0.1, [\midinote, Pkey(\val) + [0, 5], \legato, 0.2, \amp, [0.1, 0.07]]] +).play; +) + +// stop and free HSpar by player + +p.free; + + + +///////////////////////////////////////////////// + + +// HSpar with only one help synth + +h = HSpar(s, [ { |freq = 1, dev = 5, center = 65| LFDNoise3.kr(freq, dev, center) } ] ); + + +// to be used for setting synth args + +( +p = PHSpar(h, + Pwhite(0.15, 0.35, inf), // switch durations + 0, // switch index + [[\center, Pwhite(65, 80)]], // set args + [0.1, [\midinote, Pkey(\val) + Pseq([[0,-7], -2],inf), \legato, 0.3, \amp, 0.05 ]] +).play +) + +// stop and free HSpar by player + +p.free; +:: diff --git a/HelpSource/Classes/IdentityDictionary.ext.schelp b/HelpSource/Classes/IdentityDictionary.ext.schelp new file mode 100644 index 0000000..4fc99fe --- /dev/null +++ b/HelpSource/Classes/IdentityDictionary.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private::miSC_checkFxOrder, miSC_fxOrderWarnString, miSC_keysValuesEvery, miSC_keysValuesAny, miSC_putAppend, miSC_removeDrop, miSC_getPredecessors, miSC_getSuccessors, miSC_getTopoOrder, miSC_getFxOrders + +private::miSC_replaceKeys \ No newline at end of file diff --git a/HelpSource/Classes/Integer.ext.schelp b/HelpSource/Classes/Integer.ext.schelp new file mode 100644 index 0000000..523bf7b --- /dev/null +++ b/HelpSource/Classes/Integer.ext.schelp @@ -0,0 +1,36 @@ + +INSTANCEMETHODS:: + +private:: miSC_groupIndices, miSC_cubeDivision, miSC_selectCubeComponent, miSC_distinctCubePoints +private:: miSC_distinctColors, miSC_colorDeviationPairs, miSC_getCtrIndex +private:: miSC_runMsg, miSC_setMsg, miSC_setnMsg, miSC_freeMsg +private:: miSC_partMax, miSC_eqPart + +private:: miSC_isPseudoCaps, miSC_checkColorGroups + +private:: miSC_getClutch, miSC_checkFxOrder, miSC_getTopoOrder, miSC_getPredecessors, miSC_getSuccessors, miSC_getFxOrders, miSC_zeroIdRank, miSC_fxIdRank + + + +private:: miSC_streamifySieveItems, miSC_fxOrderWarnString + + +method:: lcmByGcd + +Calculates the least common multiple by using the greatest common divisor. This can avoid problems with large numbers. +See link::Tutorials/Sieves_and_Psieve_patterns#4b:: + +argument::... args +Integers + + + +method:: lcmByFactors + +Calculates the least common multiple by prime factors. This can avoid problems with large numbers. +Returns an array with lcm as first item, an array with prime factors of lcm as second item and an array of receiver's and all arguments' prime factors. +See link::Tutorials/Sieves_and_Psieve_patterns#4b:: + +argument::... args +Integers + diff --git a/HelpSource/Classes/MemoRoutine.schelp b/HelpSource/Classes/MemoRoutine.schelp new file mode 100644 index 0000000..552b843 --- /dev/null +++ b/HelpSource/Classes/MemoRoutine.schelp @@ -0,0 +1,227 @@ +CLASS:: MemoRoutine +summary:: Routine-like object which stores last values +categories::Libraries>miSCellaneous>PSx stream patterns, Streams-Patterns-Events>PSx stream patterns +related:: Overviews/miSCellaneous, Tutorials/PSx_stream_patterns, Classes/Routine, Classes/PS, Classes/PSdup, Classes/PSrecur + + +DESCRIPTION:: + + +A MemoRoutine behaves like a Routine, though it is not defined as a subclass of it. It stores last values, the maximum buffer size can be defined. MemoRoutine is internally used by PSx and related Pattern classes, which therefore also remember their last value(s). + + +CLASSMETHODS:: + +method::new + +Creates a MemoRoutine instance with the given Function. + +argument::func +Function to instantiate the Routine with. + +argument::stackSize +Call stack depth, defaults to 512. + +argument::bufSize +Number of last values to store, defaults to 1. + +argument::copyItems +Determines if and how to copy items, which are returned by method next +(run, value, resume) and which are either non-Sets or member of Sets, into the buffer. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). +Other values are interpreted as 0. Defaults to 0. + +0: storage of original item + +1: storage of copied item + +2: storage of deepCopied item + +argument::copySets +Determines if to copy Sets (and hence Events), +which are returned by method next (run, value, resume), into the buffer. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). +Other values are interpreted as 0. Defaults to 1. + +0: storage of original Set + +1: storage of copied Set + +note:: + +The distinction of copying items and sets makes sense in the case of event streams. Per default Events are copied (strong::copySets:: == 1), not their values (strong::copyItems:: == 0). By playing Events those are used to store additional data (synth ids, msgFuncs …) which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use MemoRoutine - copied Events will not contain this additional data. If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured then copying makes no sense, this is the normal case, so strong::copyItems:: defaults to 0. When going to alter the ouput, you might want to set strong::copyItems:: to 1 for a MemoRoutine returning simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set strong::copySets:: to 1 and strong::copyItems:: to 2 (an option strong::copySets:: == 2 doesn't exist as it would be contradictory in combination with strong::copyItems:: < 2). + +:: + + +INSTANCEMETHODS:: + + +method::next + +argument::inval +Same conventions with method yield as with aRoutine.next. + + +method::value +Same as next. + +method::resume +Same as next. + +method::run +Same as next. + +method::lastValue +Last value. + +method::lastValues +Instance variable getter method for array of stored last values. + +method::at +Returns ith item of array of last values (keep in mind reversed order: last value first). + +method::bufSize +Size of array of last values. + +method::reset +Resets the MemoRoutine by resetting its Routine. + +method::stop +Stops the MemoRoutine by stopping its Routine. + +method::count +Instance variable getter and setter methods. +Counts each call of next / value / resume / run. + +method::copyItems +Instance variable getter and setter methods. +If used directly the Integer copy code must be passed (see above). + +method::copySets +Instance variable getter and setter methods. +If used directly the Integer copy code must be passed (see above). + +method::routine +Instance variable getter and setter methods. + + + + +EXAMPLES:: + +code:: + +( +// a MemoRoutine + +m = MemoRoutine( + { |inval| 1000.do { |i| inval = i.yield } }, + bufSize: 50 +); +) + +m.nextN(5); + + +// get last value + +m.lastValue; + +m[0]; + + +// get last values, order is from last to earlier + +m.lastValues; + + +// get value before last value + +m[1]; + + + +// get more values + +m.nextN(100); + + + +// first values are lost now + +m.lastValues; + + +// as loop in m is restricted you might call .all +// as stop is indicated by the return of nil, +// the array lastValues contains nil as first item + +m.all; + +m.lastValues; + + + +// Per default a MemoRoutine is just storing the last values, +// with structured data types this can cause surprises + +( +// a MemoRoutine + +m = MemoRoutine( + { |inval| var a = [[2,1], [4,3]]; 1000.do { inval = a.choose.yield } }, + bufSize: 50 +); +) + +// generate some values + +m.nextN(10); + +// apply a method on last values + +( +x = m.lastValue; +x.sort; +) + +// as sort is destructive one of MemoRoutine's arrays is altered now ! + +m.nextN(10); + + + +// to avoid such you can simply do .copy.sort which doesn't alter lastValues, +// but you can also store copied values in the buffer by passing a flag with +// instantiation of the MemoRoutine + +( +// a MemoRoutine which stores copied arrays + +m = MemoRoutine( + { |inval| var a = [[2,1], [4,3]]; 1000.do { inval = a.choose.yield } }, + bufSize: 100, + copyItems: 1 // 1, true or \true for copy, 2 or \deep for deepCopy +); +) + +m.nextN(10); + +( +x = m.lastValue; +x.sort; +) + +// order not altered with next items + +m.nextN(10); + +// however the concerned array stored as item in lastValues remains altered + +m[10]; + + + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/Method.ext.schelp b/HelpSource/Classes/Method.ext.schelp new file mode 100644 index 0000000..b6662b1 --- /dev/null +++ b/HelpSource/Classes/Method.ext.schelp @@ -0,0 +1,8 @@ + + + +INSTANCEMETHODS:: + +private:: miSC_errorString + + diff --git a/HelpSource/Classes/Nil.ext.schelp b/HelpSource/Classes/Nil.ext.schelp new file mode 100644 index 0000000..7fe7a10 --- /dev/null +++ b/HelpSource/Classes/Nil.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_asSet + + diff --git a/HelpSource/Classes/Node.ext.schelp b/HelpSource/Classes/Node.ext.schelp new file mode 100644 index 0000000..680a053 --- /dev/null +++ b/HelpSource/Classes/Node.ext.schelp @@ -0,0 +1,6 @@ + +INSTANCEMETHODS:: + +private:: miSC_runMsg, miSC_setMsg, miSC_setnMsg, miSC_freeMsg + + diff --git a/HelpSource/Classes/Object.ext.schelp b/HelpSource/Classes/Object.ext.schelp new file mode 100644 index 0000000..952a13a --- /dev/null +++ b/HelpSource/Classes/Object.ext.schelp @@ -0,0 +1,32 @@ + +INSTANCEMETHODS:: + +private:: miSC_isKindOfFixedHSindex, miSC_isKindOfFixedHSindices, miSC_isKindOfPossibleHSindices +private:: miSC_isKindOfPossibleHSstartIndices, miSC_normalizeHSstartIndices + + +private:: miSC_isGrouping, miSC_getCtrIndex, miSC_collectCopy, miSC_performWithEnvir + +private:: miSC_defNameAsArray + +private:: miSC_makeLacePat + + +private:: miSC_repTypeFactor, miSC_applyNaryFuncProxy + +private:: miSC_getEnvir + +private:: miSC_copy, miSC_getCopyCode + +private:: miSC_check + +private:: miSC_checkFxOrder, miSC_fxOrderWarnString, miSC_getFxOrderData + + +private:: miSC_isPointSel, miSC_isIntervalSel + +private:: miSC_unifySize + +private:: miSC_Dmultiply + +private:: miSC_Dmultiply2 \ No newline at end of file diff --git a/HelpSource/Classes/PHS.schelp b/HelpSource/Classes/PHS.schelp new file mode 100644 index 0000000..0ab1526 --- /dev/null +++ b/HelpSource/Classes/PHS.schelp @@ -0,0 +1,196 @@ +CLASS:: PHS +summary:: defines Pbind(s) for using synth values of a HS +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/PHS, Classes/PHSuse, Classes/PHSplayer, Classes/PHSusePlayer + + +DESCRIPTION:: +Defines Pbind(s) which, when played, can use values of a synth derived from link::Classes/HS::'s synth definition. + + +CLASSMETHODS:: + +method::new + +Creates a new PHS object. + +argument::helpSynth +A HS object. + +argument::helpSynthArgs +Collection of key / value pairs for the HS synth. + +argument::... pbindArgs +dur1, pbindData1, ... , durN, pbindDataN + +where strong::dur:: is duration value or pattern / stream of durations for corresponding Pbind(s) +and strong::pbindData:: is a collection of Pbind pairs or a collection of Pbind pair collections, +defining possibly several Pbinds with the same event timing. + +INSTANCEMETHODS:: + +method::play + +A link::Classes/PHSplayer:: object is instantiated and started using the TempoClock strong::clock::. +Quant or SimpleNumber strong::quant:: lets the player step into the quantization as soon as possible, +with respect to the necessary latency. The PHSplayer can be stopped and resumed with several options. + + +method::newPaused + +VarGui support, see link::Tutorials/HS_with_VarGui:: for examples. + +Return a new paused Synth derived from HS's ugenFunc definition, which may be passed to a VarGui object. +VarGui will automatically detect that the Synth origins from a HS definition and gui functionality wil be adapted. + +argument::args +Collection of key / value pairs for the HS synth. + +argument::latency +SimpleNumber (seconds). + + + +method::asTask + +VarGui support, see link::Tutorials/HS_with_VarGui:: for examples. + +Returns a wrapper Task, which may be passed to a VarGui object. +Playing and stopping the wrapper Task invokes playing and +stopping behaviour of the underlying PHSplayer, per default also taking control over +playing and stopping the help synth. + +argument::clock +TempoClock. + +argument::quant +Quant or SimpleNumber. + +argument::hsStop +Boolean. Determines if help synth will stop together with PHSplayer. Defaults to false. + +argument::hsPlay +Boolean. Determines if help synth will resume together with PHSplayer. Defaults to true. + +argument::newEnvir +Boolean. Determines if Task will be played in a newly generated environment. Defaults to true. +This option especially becomes important when PHS's strong::pbindData:: contains functional code with +environmental variables. + +argument::removeCtrWithCmdPeriod +Boolean. Defaults to true. +Determines if notification of PHSplayer will be stopped with CmdPeriod. + + + + + + + +EXAMPLES:: + +code:: + + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// define a HS with args + +h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) }); + + +// two Pbinds with different event timing reading from one help synth + +( +p = PHS(h, nil, // default help synth args + Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val), \amp, 0.08 ], + 0.1, [ \midinote, Pkey(\val) + 9.5 + Pxrand([0, 2, 5],inf), \amp, 0.06 ] +).play; +) + +// stop player and free HS, ready to be played again with the same or another PHS + +p.free; + + +// now with synth args + +( +p = PHS(h, [\freq, 2, \dev, 20], // more oscillation + Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val) - [0, 5, 10], \amp, 0.06 ], + 0.1, [ \midinote, Pkey(\val) + 9.5 + Pxrand([0, 4, 7],inf), \amp, 0.06 ] +).play; +) + + +// stop player and free HS + +p.free; + + +// let PHS define two Pbinds with same event timing, one mostly pausing + +( +p = PHS(h, [], 0.16, + [ [ \midinote, Pkey(\val), \amp, 0.1], + [ \midinote, Pkey(\val) + [-7, 4, 7], + \amp, Pwrand([0.04, 0.08], [0.8, 0.2], inf), + \type, Pkey(\val).collect { |x| x.asInteger.even.if { \note }{ \rest } } ] + ] +).play; +) + + +// stop player and free HS + +p.free; +:: + +Order of execution: three Pbinds defined, scheduling slightly time-shifted internally, +so references can be established. + +Printout of variables which may be used within a PHS definition, +code::timeGrains:: is just a time ID, depending on granularity, not used for scheduling. +code::demandIndex:: indicates the index of the stream of durations, +posted code::demandIndex:: = 1, as two pbinds are using duration stream #0. + +code:: +( +p = PHS(h, [], + 0.16, + [ [ \midinote, Pkey(\val) + Pseq([0,2], inf), \amp, 0.06], + [ \midinote, Pkey(\val) + [-7, 4, 7], + \amp, Pwrand([0.06,0.1], [0.8,0.2], inf), + // "random" appearance of middle voice chords depending on synth values + \type, Pkey(\val).collect { |x| ~middle = x.asInteger.even.if { \note }{ \rest } } ] + ], + Pseq([0.32, 0.16], inf), + [ [ \midinote, Pkey(\val) + [15, 20, 25], + \legato, 0.2, + \amp, 0.025, + // upper voice is playing in case of middle voice rest + \type, Pkey(\val).collect { |x| (~middle == \rest).if { \note }{ \rest } }, + \post, Pfunc { |e| e.use { + "demandIndex: ".post; ~demandIndex.postln; + "timeGrains: ".post; ~timeGrains.postln; + "dur: ".post; ~dur.postln; + "val: ".post; ~val.postln; + "================================".postln; + } + } + ] ] +).play; +) + + +// stop player and free HS + +p.free; + +:: + diff --git a/HelpSource/Classes/PHSpar.schelp b/HelpSource/Classes/PHSpar.schelp new file mode 100644 index 0000000..6b7ee69 --- /dev/null +++ b/HelpSource/Classes/PHSpar.schelp @@ -0,0 +1,415 @@ +CLASS:: PHSpar +summary:: defines Pbind(s) for using synth values of a HSpar +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/HSpar, Classes/PHSparUse, Classes/PHSparPlayer, Classes/PHSusePlayer + + +DESCRIPTION:: +Defines Pbind(s) which, when played, can use values of synths derived from link::Classes/HSpar::'s synth definitions. + + +CLASSMETHODS:: + +method::new + +Creates a new PHSpar object. + +argument::helpSynthPar +A HSpar object. + +argument::switchDur +Duration value or pattern / stream of durations determining the times of HSpar synth switches. + +argument::switchIndex +Index or pattern / stream of indices determining HSpar's synth definition to switch to. +Defaults to 0. + +argument::helpSynthArgs +Collection of Pbind pair collections (size = number of strong::helpSynthPar::'s help synths), +defining synth args to be set at switch times. + +argument::pbindArgs +Collection of the form strong::[ dur1, pbindData1, ... , durN, pbindDataN:: strong::]::, whereby +strong::dur:: is a duration value or pattern / stream of durations for the corresponding Pbind(s) and +strong::pbindData:: is a collection of Pbind pairs or a collection of Pbind pair collections, +defining possibly several Pbinds with same event timing. + +argument::hsIndices +Per default values are taken from the currently switched help synth. +Explicitely given strong::hsIndices:: allow reference to values of other help synths from the +corresponding Pbind(s). See the examples below. +Expects a collection of valid hsIndex values resp. patterns / streams of valid hsIndex values. +A valid hsIndex value is a valid help synth index or a collection of valid help synth indices. +The collection's size must equal strong::N::, the number of strong::pbindArgs::'s event timings. + +argument::switchOn +Boolean or Pattern / Stream of Booleans, determining if switched help synths should be resumed. +Defaults to false. + +argument::switchOff +Boolean or Pattern / Stream of Booleans, determining if help synths, +which are left at a switch, should be paused. +Defaults to false. + +argument::set +Boolean or Pattern / Stream of Booleans, determining if next synth input values, defined in strong::helpSynthArgs::, should be +taken for setting the synth. The first help synth args are always set. Defaults to true. + +argument::hsStartIndices +A valid help synth index, a collection of valid help synth indices or one of the symbols: \all, \none. +Determines which help synths should be started at the beginning in addition to the one of the first switch index. +Help synths of other than first switch index are played with default args. + + +INSTANCEMETHODS:: + +method::newPaused + +VarGui support, see link::Tutorials/HS_with_VarGui:: for examples. + +Return a collection of new paused Synth(s) derived from HSpar's ugenFunc definition(s), which may be passed to a VarGui object. +VarGui will automatically detect the origin from a HSpar definition and gui functionality wil be adapted. + +argument::args +Collection of collection(s) of key / value pairs for the HSpar synth(s). + +argument::latency +SimpleNumber (seconds). + + + +method::asTask + +VarGui support, see link::Tutorials/HS_with_VarGui:: for examples. + +Returns a wrapper Task, which may be passed to a VarGui object. +Playing and stopping the wrapper Task invokes playing and +stopping behaviour of the underlying PHSparPlayer, per default also taking control over +playing and stopping the help synth(s). + +argument::clock +TempoClock. + +argument::quant +Quant or SimpleNumber. + +argument::hsStop +Boolean, Integer or SequenceableCollection of Integers determining help synth indices. +Determines if help synth(s) will stop together with PHSparPlayer. Defaults to false. + +argument::hsPlay +Boolean, Integer or SequenceableCollection of Integers determining help synth indices. +Determines if help synth(s) will resume together with PHSparPlayer. Defaults to true. + +argument::switchStop +Boolean. Determines if switching will stop together with PHSparPlayer. Defaults to true. + +argument::newEnvir +Boolean. Determines if Task will be played in a newly generated environment. Defaults to true. +This option especially becomes important when PHSpar's strong::pbindData:: contains functional code with +environmental variables. + +argument::removeCtrWithCmdPeriod +Boolean. Defaults to true. +Determines if notification of PHSparPlayer will be stopped with CmdPeriod. + + + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +// define a HSpar with two help synth definitions + +( +h = HSpar(s, [ + { |freq = 1, dev = 5, center = 65| + LFDNoise3.kr(freq, dev, center) }, + { |freq = 1, dev = 5, center = 75, addFreq = 0.1, addDev = 5| + LFTri.kr(freq, 0, dev, center) + SinOsc.kr(addFreq, 0, addDev) } +]); +) + +// define a PHSpar to switch between these two +// reference to currently switched help synth via ~val +// note that pbindArgs, different from PHS, have to be given as collection + +( +p = PHSpar(h, + 3, // switch duration + Pseq([0,1],inf), // switch indices + // center of help synth #0 is reset at every switch, default values for help synth #1 : + [ [\center, Pseq([65, 90], inf)], nil], + // ~val refers to current switch : + [0.1, [\midinote, Pkey(\val) + Pseq([0,1],inf), \legato, 0.2 ] ] +).play; +) + +// stop and free HSpar + +p.free; + + + +// no need to define a switch pattern +// default switch index = 0, default switch duration = inf +// hsIndices value \all causes that all help synth values at +// corresponding Pbind times are accesible via ~vals + +( +p = PHSpar(h, + pbindArgs: [0.1, [\midinote, Pkey(\vals) /* collection, thus played as interval */ + Pseq([0,1],inf), + \legato, 0.2 ] ], + hsIndices: [ \all ] +).play; +) + +p.free; + + + +// this is a bit wasteful as always both help synth values are demanded via the OSCresponder mechanism: +// see printed (serverToClient) OSC traffic + +( +h.postOSC = true; + +p = PHSpar(h, + pbindArgs: [0.1, [\midinote, Pkey(\vals).collect(_.at(1)) /* take only the second */ + + Pseq([0,1],inf), \legato, 0.2 ] ], + hsIndices: [ \all ] +).play; +) + +p.free; + + + +// the index may be determined by hsIndices +// only the needed help synth value is demanded and can be referenced via ~thisVal: +// compare printed OSC traffic + +( +p = PHSpar(h, + pbindArgs: [0.1, [\midinote, Pkey(\thisVal) /* take value determined by hsIndices */ + + Pseq([0,1],inf), \legato, 0.2 ] ], + hsIndices: [ 1 ] +).play; +) + +( +p.free; +h.postOSC = false; +) + + +// hsIndices may contain patterns +// only the needed help synth value is demanded and can be referenced via ~thisVal (or ~theseVals) : + +( +p = PHSpar(h, + pbindArgs: [0.1, [\midinote, Pkey(\thisVal) + Pseq([0,1],inf), \legato, 0.2 ] ], + hsIndices: [ Prand([0,1], inf) ] +).play; +) + +p.free; + + + +// hsIndices also accepts collections of indices or patterns thereof, +// referenced by ~theseVals (which is always a collection) + +( +p = PHSpar(h, + pbindArgs: [0.1, [\midinote, Pkey(\theseVals) + Pseq([0,1],inf), \legato, 0.2 ] ], + hsIndices: [ Pstutter(Pwhite(5,10), Pxrand([0, 1, [0,1]], inf)) ] +).play; +) + +p.free; + + + +// two Pbinds with different event timing +// hsIndices specified for each + +( +p = PHSpar(h, + // "+" wraps collections, so if ~theseVals is an interval then + // ~midinote consists of the two added sevenths [-5, 5], [0, 10], + // otherwise ~midinote is a chord of fourths + pbindArgs: [0.2, [\midinote, Pkey(\theseVals) + [-5, 0, 5,10] , \legato, 0.2, \amp, 0.05 ], + 0.1, [\midinote, Pkey(\thisVal) + Pseq([0,1],inf), \legato, 0.2, \amp, 0.08 ]], + hsIndices: [ Pstutter(Pwhite(5,10), Pxrand([0, 1, [0,1]], inf)), 0] +).play; +) + +p.free; + + + +// the switched indices can be referenced via the hsIndices arg by symbol \switch +// \all is synonym to [0,1] in the last example + +( +p = PHSpar(h, + Pwhite(0.5, 1.5),// switch duration + Pseq([0,1],inf), // switch indices + [ [], [] ], // default values for help synths + // "+" wraps collections, so if ~theseVals is an interval then + // ~midinote consists of the two added sevenths [-5, 5], [0, 10], + // otherwise ~midinote is a chord of fourths + [ 0.2, [\midinote, Pkey(\theseVals) + [-5, 0, 5,10] , \legato, 0.2, \amp, 0.05 ], + 0.1, [\midinote, Pkey(\thisVal) + Pseq([0,1],inf), \legato, 0.2, \amp, 0.08 ] ], + [ Pstutter(Pwhite(5,10), Pxrand([0, 1, \all], inf)), \switch ] + // single line switches between trill and arpeggio +).play; +) + +p.free; + + +////////////////////////////////////////////////////////////////////////////////// + + +// HSpar with two help synth definitions + +( +h = HSpar(s, [ + { |start = 90, end = 60, dur = 10, add = 0| + XLine.kr(start, end, dur) + add; }, + { |freq = 0.3, dev = 15, center = 60, phase = 0, add = 0| + LFTri.kr(freq, phase, dev, center + add); } +]); +) + + +// switch between two help synths +// both help synths are run from the start (default hsStartIndices = true) +// help synths of switch index are paused when index is left (switchOff: true) and +// resumed when index is given (switchOn: true) +// movement downwards needs more than 10 seconds defined by XLine + +( +p = PHSpar(h, + Pwhite(0.3,1.0), // switch duration + Pseq([0,1], inf), // switch indices, + // distinguish help synth values by reference to ~switchIndex + pbindArgs: [0.12, [\midinote, Pkey(\val) + + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ], + switchOn: true, + switchOff: true +).play; +) + +p.free; + + + +// never pause help synth #0, always pause #1 +// end value of help synth #0 reached after 10 seconds + +( +p = PHSpar(h, + Pwhite(0.3,1.0), // switch duration + Pseq([0,1], inf), // switch indices, + // distinguish help synth values by reference to ~switchIndex + pbindArgs: [0.12, [\midinote, Pkey(\val) + + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ], + switchOn: true, + switchOff: Pseq([false, true], inf) // next pause value with next switch index +).play; +) + +p.free; + + + +// hsStartIndices: define which help synths should be run from the beginning (only #1) +// help synth #0 is run when switched first (switchOn: true) +// movement downwards starts after 5 seconds + +( +p = PHSpar(h, + Pseq([5, Pwhite(0.3,1.0, inf)]), // switch duration + Pseq([1,0], inf), // switch indices, + // distinguish help synth values by reference to ~switchIndex + pbindArgs: [0.12, [\midinote, Pkey(\val) + + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ], + switchOn: true, + hsStartIndices: 1 // \none (except the switched) or [1] would also do +).play; +) + +p.free; + + + +// set: determines whether new values should be polled from +// streams (defined in helpSynthArgs) at switch time. +// Here only at every second switch a new add value (register change) is set. + +( +p = PHSpar(h, + Pwhite(0.3, 0.5, inf), // switch duration + Pseq([0,1], inf), // switch indices, + [ [\add, Pseq([0, 10.5, 21], inf) ], [\add, Pseq([0, 10.5, 21], inf), \dev, 5] ], // helpSynthArgs + // distinguish help synth values by reference to ~switchIndex + pbindArgs: [0.12, [\midinote, Pkey(\val) + + Pkey(\switchIndex).collect(switch(_, 0, [0,2.5], 1, [0,7])), \legato, 0.2 ] ], + set: Pstutter(2, Pseq([true, false], inf)) // next set value with next switch index +).play; +) + +p.free; + + + +// now things quite mixed up + +// basic pitches chosen by index sequence defined in hsIndices, reference by Pkey(\theseVals) +// switchIndex only determines the added interval +// if theseVals contains only one value the determined interval is based on this value +// ([a] + [x, y] = [a + x, a + y]), +// otherwise it is just added to the interval of theseVals +// ([a, b] + [x, y] = [a + x, b + y]) + +// printout of variables which may be used within a PHSpar definition +// timeGrains is just a time ID, depending on granularity, not used for scheduling + +( +p = PHSpar(h, + Pwhite(0.3,1.0), // switch duration + Pseq([0,1], inf), // switch indices, + // distinguish added interval by reference to ~switchIndex + pbindArgs: [0.12, [ + \midinote, Pkey(\theseVals) + Pkey(\switchIndex).collect(switch(_, 0, [0, 2.5], 1, [0, 7])), + \legato, 0.2, + \post, Pfunc {|e| e.use { + "demandIndex: ".post; ~demandIndex.postln; + "timeGrains: ".post; ~timeGrains.postln; + "dur: ".post; ~dur.postln; + "switchIndex: ".post; ~switchIndex.postln; + "vals: ".post; ~vals.postln; + "val: ".post; ~val.postln; + "theseIndices: ".post; ~theseIndices.postln; + "theseVals: ".post; ~theseVals.postln; + "thisVal: ".post; ~thisVal.postln; + "================================".postln; + } + } + ]], + hsIndices: [ Pstutter(Pwhite(5,10), Pxrand([ 0, 1, \all ], inf)) ] +).play; +) + +p.free; + + +:: diff --git a/HelpSource/Classes/PHSparPlayer.schelp b/HelpSource/Classes/PHSparPlayer.schelp new file mode 100755 index 0000000..b948acd --- /dev/null +++ b/HelpSource/Classes/PHSparPlayer.schelp @@ -0,0 +1,291 @@ +CLASS:: PHSparPlayer +summary:: PHSpar player object +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/HSpar, Classes/PHSpar, Classes/PHSparUse, Classes/PHSusePlayer + +DESCRIPTION:: +Implicitely instantiated when link::Classes/PHSpar::'s play method is called, allows stopping and resuming with options also concerning the help synth. + + +CLASSMETHODS:: + +method::new + +Creates a new PHSparPlayer object. + +argument::pHelpSynthPar +A PHSpar object. + + +INSTANCEMETHODS:: + +method::play + +argument::clock +A TempoClock object. If not assigned, takes the default TempoClock. + +argument::quant +A Quant object. Makes the player start at the next grid that gives enough time for latency. + +argument::hsPlay +Boolean. Determines if help synth should start. Defaults to true. + +argument::switchPlay +Boolean. Determines if switch pattern should play. Defaults to true. + +argument::pbindPlay +Boolean. Determines if Pbind(s) should play. Defaults to true. + +argument::quantBufferTime +SimpleNumber (seconds). Calculated time to include latency for "stepping in" +is lengthened by this value. Defaults to 0.2. + + +method::stop + +argument::hsStop +Boolean. Determines if help synth should pause. Defaults to false. + +argument::switchStop +Boolean. Determines if switch pattern player should pause. Defaults to false. + +argument::pbindStop +Boolean. Determines if Pbind player(s) should pause. Defaults to true. + +argument::addAction +Function to be evaluated at receive time. + +method::pause + += strong::stop:: + + +method::free + +Stop the PHSparPlayer and all PHSusePlayers that are using the same HSpar, also free the HSpar. + +Note:: strong::stop:: (= strong::pause::) allows resuming the player - strong::free:: resets, player can be started again. +:: + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// define PHSpar and several users + +( +h = HSpar(s, [ + { |freq = 2, dev = 7, center = 60| + LFDNoise3.kr(freq, dev, center) }, + { |freq = 5, dev = 10, center = 80| + LFDNoise3.kr(freq, dev, center) } +]); + +~p1 = PHSpar(h, + pbindArgs: [0.1, [\midinote, Pkey(\thisVal), \legato, 0.2, \amp, 0.06 ] ], + hsIndices: [0] ); + +~p2 = PHSparUse(h, + pbindArgs: [0.2, [\midinote, Pkey(\thisVal) - 3,\legato, 0.2, \amp, 0.06 ]], + hsIndices: [1] ); + +~p3 = PHSparUse(h, + pbindArgs: [Pn(Pshuf([0.2, 0.1, 0.1], 1), inf), [\midinote, Pkey(\theseVals) + 5, \legato, 0.2, \amp, 0.06 ]], + hsIndices: [[0, 1]] ); + +~p4 = PHSparUse(h, + pbindArgs: [Pn(Pshuf([0.2, 0.1, 0.1], 1), inf), [\midinote, Pkey(\theseVals) + 8, \legato, 0.2, \amp, 0.06 ]], + hsIndices: [[0, 1]] ); + +c = TempoClock.new; +q = Quant(0.8, 0); +) + + +// start PHSparPlayer with help synth #0 + +~x1 = ~p1.play(c,q); + + +// add a PHSusePlayer using help synth #1 + +~x2 = ~p2.play(c,q); + + +// add a PHSusePlayer using both help synths + +~x3 = ~p3.play(c,q); + + +// and another one + +~x4 = ~p4.play(c,q); + + +// stop PHSparPlayer, help synths keep playing + +~x1.stop; + + +// stop a PHSusePlayer + +~x2.stop; + + +// and another one, only player ~x4 left + +~x3.stop; + + +// resume ~x1 + +~x1.play(c,q); + + +// stop only help synth #1 + +~x1.stop(hsStop: 1, pbindStop: false); + + +// stop also help synth #0 and player ~x1 + +~x1.stop(hsStop: 0); + + +// now only one pbind engaged via PHSusePlayer ~x4, but help synths may be controlled via PHSparPlayer ~x1 ! +// resume both help synths + + +~x1.play(hsPlay: [0,1], pbindPlay: false); + + +// stop them again, using keyword + +~x1.stop(hsStop: \all, pbindStop: false); + + +// stop last remaining PHSusePlayer via the "leading" PHSparPlayer and free HSpar + +~x1.free; + + + + + +//////////////////////////////////////////////////// + + +( +// define HSpar: two sine waves with opposite phases + +h = HSpar(s, [ + { |freq = 0.25, dev = 5, center = 70| + SinOsc.kr(freq, 3pi/2, dev, center) }, + { |freq = 0.25, dev = 5, center = 70| + SinOsc.kr(freq, pi/2, dev, center) } +]); + +// one stream shared by both switch indices +// goal: repetition of sine wave segment, alternate register, small random add for pitch + +~pitchBaseStream = (Pseq([60,80],inf) + Pwhite(0.0,5.0)).asStream; + +p = PHSpar(h, 2, // switchDur = half phase of sine wave + Pseq([0,1], inf), // switchIndex + [\center, ~pitchBaseStream] ! 2, + [0.25, [\midinote, Pkey(\val) + [-5.25, 0, 4, 7.25] , \legato, 0.2, \amp, 0.06 ]] +); + +) + + +// stopping and resuming with options +// if stopped together, help synths, pbinds and switchIndex player are kept in sync for resuming +// therefore methods stop and play are blocking the player for some moments, but freeing is always possible + +// switchStop = true is blocking for the whole current switch duration - this could be reduced + +x = p.play; + + +// stop everything, keep sync: try stopping and resuming several times, leave some moments between + +x.stop(switchStop: true, hsStop: true, pbindStop: true); + +x.play; + + +// free everything + +x.free; + + + +////////////////// + +x = p.play; + + +// stop only the pbind +// try stopping and resuming several times - always ascending segments of the sine wave, pbind is "stepping in" +// as points of stepping in may differ, low slope in ascending sequences may occur at the beginning or at the end + +x.stop; // equivalent to x.stop(switchStop: false, hsStop: false, pbindStop: true) + +x.play; + + +// + +x.free; + + + +////////////////// + +x = p.play; + + +// stop everything BUT the pbind +// try stopping and resuming several times - again always ascending segments of the sine wave as +// switchIndex player and help synths are stopped and started together + +x.stop(switchStop: true, hsStop: true, pbindStop: false); + +x.play; + + +// + +x.free; + + + +////////////////// + +x = p.play; + + +// let only help synths run +// try stopping and resuming several times +// switchIndex player and help synths are relinked, other sine wave segments establish + +x.stop(switchStop: true, hsStop: false, pbindStop: true); + +x.play; + + +// + +x.free; + + + +:: diff --git a/HelpSource/Classes/PHSparUse.schelp b/HelpSource/Classes/PHSparUse.schelp new file mode 100644 index 0000000..847fab7 --- /dev/null +++ b/HelpSource/Classes/PHSparUse.schelp @@ -0,0 +1,178 @@ +CLASS:: PHSparUse +summary::defines Pbind(s) for using synth values of a HSpar +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/HSpar, Classes/PHSpar, Classes/PHSparPlayer, Classes/PHSusePlayer + +DESCRIPTION:: +Defines Pbind(s) which, when played, can use values of synths derived from link::Classes/HSpar::'s synth definitions. +Note:: Playing a PHSparUse is just an option for using an already playing help synth of a HSpar, which requires link::Classes/PHSpar:: first. +See link::Guides/Guide_to_HS_and_HSpar::, "Working Scheme". +:: + +CLASSMETHODS:: + +method::new + +Creates a new PHSparUse object. + +argument::helpSynth +A HSpar object. + +argument::pbindArgs +Collection of the form strong::[ dur1, pbindData1, ... , durN, pbindDataN:: strong::]::, whereby +strong::dur:: is a duration value or pattern / stream of durations for the corresponding Pbind(s) and +strong::pbindData:: is a collection of Pbind pairs or a collection of Pbind pair collections, +defining possibly several Pbinds with same event timing. + +argument::hsIndices +Per default values are taken from the currently switched help synth. +Explicitely given strong::hsIndices:: allow reference to values of other help synths from the corresponding Pbind(s). +Expects a collection of valid hsIndex values resp. patterns / streams of valid hsIndex values. +A valid hsIndex value is a valid help synth index or a collection of valid help synth indices. + + +INSTANCEMETHODS:: + +method::play + +A link::Classes/PHSusePlayer:: object is instantiated and started using the TempoClock strong::clock::. +Quant or SimpleNumber strong::quant:: lets the player step into the quantization as soon as possible, +with respect to the necessary latency. The PHSusePlayer can be stopped and resumed with options. + + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// HSpar with two synth definitions + +( +h = HSpar(s, [ + { |freq = 1, dev = 10, center = 80| + LFDNoise3.kr(freq, dev, center) }, + { |freq = 0.5, dev = 5, center = 60, addFreq = 0.1, addDev = 5| + LFDNoise3.kr(freq, dev, center) + SinOsc.kr(addFreq, 0, addDev) } +]); + +c = TempoClock(1); +q = 0.12; +) + + +// Play Pbind (via PHSpar) to poll values from one or both synths, +// according to the pattern given to hsIndices. +// Random add with adverb "+.x" adds an interval also to each of two simultaneous synth values. + +( +x = PHSpar(h, + pbindArgs: [0.12, [\midinote, Pkey(\theseVals).collect(_ +.x [7, 8, [0,7], [-1,8]].choose), + \legato, 0.2, \amp, 0.05 ]], + hsIndices: [ Prand([0,1,\all], inf)] +).play(c,q); +) + + +// "stepping in" with second player at (with respect to latency) next possible time on grid + +( +y = PHSparUse(h, + pbindArgs: [ Prand([0.36, 0.48],inf), + [\midinote, Pkey(\theseVals) + [1, 1.75, 2.5, 3.25, 4, 4.75, 5.5, 6.25], + \legato, 0.2, \amp, Prand([0.03, 0.05, 0.07], inf) ]], + hsIndices: [ Pn(Pshuf([0,0,1,1],1), inf) ] +).play(c,q); +) + + +// stop x, help synths still playing, producing values for y + +x.stop; + + +// resume x + +x.play(c,q); + + +// freeing the PHSparPlayer also stops all "related" PHSusePlayers and frees the HSpar + +x.free; + + + +///////////////////////////////////////////////////////////////////////////////// + +// Instead of using PHSuse / PHSparUse objects in order to have seperate players +// it's, of course, also possible to define several HS / HSpar objects independently. +// As before players can be synced by quantization. + +( +h = HSpar(s, [ + { |freq = 0.5, dev = 5, center = 70| + LFDNoise3.kr(freq, dev, center) }, + { |freq = 0.2, dev = 5, center = 62, addFreq = 0.1, addDev = 2| + LFTri.kr(freq, 0, dev, center) + SinOsc.kr(addFreq, 0, addDev) } +]); +c = TempoClock.new; +q = 0.24; +) + + +// first player using a HSpar + +( +x = PHSpar(h, + pbindArgs: [ + Pstutter(Pwhite(5,10), Pseq([0.12, 0.16], inf)), + [\midinote, Pkey(\thisVal) + Pseq([[2, 5], [1, 6], [0, 7]], inf), \legato, 0.2, \amp, 0.07], + 0.24, [\midinote, Pkey(\thisVal) + [-6, -1, 3], \legato, 0.2, \amp, 0.07]], + hsIndices: [0, 1] +).play(c,q); +) + + +// define an additional HS + +( +k = HS(s, {|start = 90, end = 50, dur = 10| XLine.kr(start, end, dur); }); +) + + +// start synced player + +( +r = PHS(k, + [\start, { rrand(85, 100) }], + 0.12, [\midinote, Pkey(\val) + [0, 3.5], \legato, 0.2, \amp, 0.07] +); +y = r.play(c,q); +) + + +// stop and free (reset) second player and HS + +y.free; + + +// play again - a new help synth is started + +y.play(c,q); + + +// stop and free first player and HSpar + +x.free; + + +// stop and free second one and HS + +y.free; + + +:: diff --git a/HelpSource/Classes/PHSplayer.schelp b/HelpSource/Classes/PHSplayer.schelp new file mode 100755 index 0000000..bc3ce1c --- /dev/null +++ b/HelpSource/Classes/PHSplayer.schelp @@ -0,0 +1,104 @@ +CLASS:: PHSplayer +summary:: PHS player object +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/HS, Classes/PHS, Classes/PHSuse, Classes/PHSusePlayer + +DESCRIPTION:: +Implicitely instantiated when link::Classes/PHS::'s play method is called, allows stopping and resuming with options also concerning the help synth. + + +CLASSMETHODS:: + +method::new + +Creates a new PHSplayer object. + +argument::pHelpSynth +A PHS object. + + +INSTANCEMETHODS:: + +method::play + +argument::clock +A TempoClock object. If not assigned, takes the default TempoClock. + +argument::quant +Quant or SimpleNumber. Makes the player start at the next grid that gives enough time for latency. + +argument::hsPlay +Boolean. Determines if help synth should also start. Defaults to true. + +argument::pbindPlay +Boolean. Determines if Pbind(s) should play. Defaults to true. + +argument::quantBufferTime +SimpleNumber (seconds). Calculated time to include latency for "stepping in" +is lengthened by this value. Defaults to 0.2. + +method::stop + +argument::hsStop +Boolean. Determines if help synth should stop. Defaults to false. + +argument::pbindStop +Boolean. Determines if Pbind player(s) should stop. Defaults to true. + +argument::addAction +Function to be evaluated at receive time. + +method::pause + += strong::stop:: + +method::free + +Stop the PHSplayer and all PHSusePlayers that are using the same HS, also free the HS. + +Note:: strong::stop:: (= strong::pause::) allows resuming the player - strong::free:: resets, player can be started again. +:: + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// define HS, PHS - play + +( +h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) }); + +p = PHS(h, nil, // default help synth args + Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val), \amp, 0.1 ], + 0.1, [ \midinote, Pkey(\val) + 9.5 + Pxrand([0, 2, 5],inf), \amp, 0.08 ] +).play; +) + + +// stop only help synth + +p.stop(hsStop: true, pbindStop: false); + + +// stop pbind + +p.stop; + + +// resume help synth and eventstream player + +p.play(hsPlay: true, pbindPlay: true); + + +// stop player and free HS + +p.free; + + +:: diff --git a/HelpSource/Classes/PHSuse.schelp b/HelpSource/Classes/PHSuse.schelp new file mode 100644 index 0000000..1281f52 --- /dev/null +++ b/HelpSource/Classes/PHSuse.schelp @@ -0,0 +1,127 @@ +CLASS:: PHSuse +summary:: defines Pbind(s) for using synth values of a HS +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/HS, Classes/PHS, Classes/PHSplayer, Classes/PHSusePlayer + +DESCRIPTION:: +Defines Pbind(s) which, when played, can use values of a synth derived from link::Classes/HS::'s synth definition. Note::Playing a PHSuse is just an option for using an already playing help synth of a HS, which requires link::Classes/PHS:: first. See link::Guides/Guide_to_HS_and_HSpar::, "Working Scheme". +:: + +CLASSMETHODS:: + +method::new + +argument::helpSynth +A HS object. + +argument::... pbindArgs +dur1, pbindData1, ... , durN, pbindDataN + +where strong::dur:: is duration value or pattern / stream of durations for corresponding Pbind(s) +and strong::pbindData:: is a collection of Pbind pairs or a collection of Pbind pair collections, +defining possibly several Pbinds with the same event timing. + +INSTANCEMETHODS:: + +method::play + +A link::Classes/PHSusePlayer:: object is instantiated and started using the TempoClock strong::clock::. +Quant or SimpleNumber strong::quant:: lets the player step into the quantization as soon as possible, +with respect to the necessary latency. The PHSusePlayer can be stopped and resumed with options. + + +method::asTask + +VarGui support, see link::Tutorials/HS_with_VarGui:: for examples. + +Returns a wrapper Task, which may be passed to a VarGui object. +Playing and stopping the wrapper Task invokes playing and +stopping behaviour of the underlying PHSusePlayer. + +argument::clock +TempoClock. + +argument::quant +Quant or SimpleNumber. + +argument::newEnvir +Boolean. Determines if Task will be played in a newly generated environment. Defaults to true. +This option especially becomes important when PHSuse's strong::pbindData:: contains functional code with +environmental variables. + +argument::removeCtrWithCmdPeriod +Boolean. Defaults to true. +Determines if notification of PHSusePlayer will be stopped with CmdPeriod. + + + + + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// two Pbinds getting values for pitches from a single HS + +h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) }); + + +// define Pbinds via PHS and PHSuse separately, +// choose quant that allows synchronization + +( +u = PHS(h, nil, // default help synth args + 0.15, [ \midinote, Pkey(\val) + [-5, 0], \amp, 0.065 ]); + +v = PHSuse(h, 0.15, + [ \midinote, 130 - Pkey(\val) + [0, 5], // mirror at center frequency + \amp, Pwrand([0.03, 0.07], [0.7, 0.3], inf) ]); + +c = TempoClock(1); +q =0.3; +) + + +// start first player + +x = u.play(c,q); + + +// "stepping in" with second player at (with respect to latency) next possible time on grid + +y = v.play(c,q); + + +// stop x, help synth still playing, producing values for y + +x.stop; + + +// define and play another PHSuse + +( +w = PHSuse(h, 0.15, + [ \midinote, 130 - Pkey(\val) + [0, 5] + Pwhite(7.0, 10.0), // mirror at center frequency + random add + \amp, Pwrand([0.03, 0.07], [0.7, 0.3], inf) ]); + +z = w.play(c,q); +) + + +// resume x + +x.play(c,q); + + +// freeing the PHSplayer also stops all "related" PHSusePlayers and frees the HS + +x.free; + + +:: diff --git a/HelpSource/Classes/PHSusePlayer.schelp b/HelpSource/Classes/PHSusePlayer.schelp new file mode 100755 index 0000000..59007cb --- /dev/null +++ b/HelpSource/Classes/PHSusePlayer.schelp @@ -0,0 +1,104 @@ +CLASS:: PHSusePlayer +summary:: player object for PHSuse and PHSparUse +categories::Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Guide_to_HS_and_HSpar, Tutorials/HS_with_VarGui, Classes/HS, Classes/PHS, Classes/PHSuse, Classes/PHSplayer + +DESCRIPTION:: +Implicitely instantiated when link::Classes/PHSuse::'s or link::Classes/PHSparUse::'s play method is called. + + +CLASSMETHODS:: + +method::new + +Creates a new PHSusePlayer object. + +argument::pHelpSynthUse +A PHSuse or PHSparUse object. + +INSTANCEMETHODS:: + +method::play + +argument::clock +A TempoClock object. If not assigned, takes the default TempoClock. + +argument::quant +Quant or SimpleNumber. Makes the player start at the next grid that gives enough time for latency. + +argument::quantBufferTime +SimpleNumber (seconds). Calculated time to include latency for "stepping in" +is lengthened by this value. Defaults to 0.2. + +method::stop + +argument::addAction +Function to be evaluated at receive time. + +method::pause += strong::stop:: + + +method::free + +Only free this PHSusePlayer - the PHSplayer / PHSparPlayer, which is using the same HS / HSpar, is not affected. + +Note:: strong::stop:: (= strong::pause::) allows resuming the player - strong::free:: resets, player can be started again. +:: + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// define HS, PHS, PHSuse + +( +h = HS(s, { |freq = 0.5, dev = 10, center = 65| LFDNoise3.kr(freq, dev, center) }); + +u = PHS(h, nil, // default help synth args + // two pbinds with different timing + Prand([0.4, 0.2],inf), [ \midinote, Pkey(\val) + 4, \amp, 0.07 ], + 0.1, [ \midinote, Pkey(\val) + 15 + Pxrand([0, 2, 5],inf), \amp, 0.04, \legato, 0.5 ] +); + +v = PHSuse(h, // two pbinds with different timing + Prand([0.4, 0.2],inf) , [ \midinote, Pkey(\val), \amp, 0.07 ], + 0.1, [ \midinote, Pkey(\val) + 6 + Pxrand([0, 2, 5],inf), \amp, 0.06, \legato, 0.5 ] +); + +c = TempoClock(1); +q = 0.2; +) + + +// play PHS + +x = u.play(c,q); + + +// play PHSuse + +y = v.play(c,q); + + +// stop PHSplayer + +x.stop; + + +// PHSusePlayer doesn't control HS - HS synth still running, see server window + +y.free; + + +// PHSplayer controls HS - this also stops HS synth + +x.free; + +:: diff --git a/HelpSource/Classes/PIdev.schelp b/HelpSource/Classes/PIdev.schelp new file mode 100755 index 0000000..9be0a0b --- /dev/null +++ b/HelpSource/Classes/PIdev.schelp @@ -0,0 +1,346 @@ +CLASS:: PIdev +summary:: pattern searching for numbers with integer distance from a source pattern, optionally avoiding repetitions within a span +categories:: Libraries>miSCellaneous>Other patterns, Libraries>miSCellaneous>Idev suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/Idev_suite, Classes/PLIdev, Classes/DIdev + + +DESCRIPTION:: + + +DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples. + +note:: +It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples. +:: + +note:: +In contrast to DIdev, PIdev and PLIdev do *not* need to know maximum deviations (strong::minLoDev::, strong::maxHiDev::) beforehand. Thus the order of arguments is different (here strong::loDev:: and strong::hiDev:: before lookBack). +:: + + + +CLASSMETHODS:: + + +method::new + +Creates a new PIdev object. + + +argument::pattern +The source value pattern to start search from. + +argument::maxLookBack +Integer, the maximum lookback span. Fixed, defaults to 3. + +argument::loDev +Determines the current low deviation for the search. Defaults to -3. + +argument::hiDev +Determines the current high deviation for the search. Defaults to 3. + +argument::lookBack +Determines the current lookback span for avoiding repetitions. Can be modulated but must not exceed strong::maxLookBack::. If no value is passed, then strong::maxLookBack:: is taken. + +argument::thr +Threshold for equality comparison. Can be modulated, defaults to 1e-3. + +argument::length +Number of repeats. Defaults to inf. + + + +section::Examples + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + + +anchor::Ex.1:: +subsection::Ex. 1: Basic usage: random choice within region without repetitions + +code:: +// constant source (72), max deviation +/- 3 +// no repetition within 5 pitches + +( +p = Pbind( + \dur, 0.2, + \midinote, PIdev(72, 5, -3, 3).trace(prefix: "midi "), +).play; +) + +p.stop +:: + + + + +anchor::Ex.2:: +subsection::Ex. 2: Variable deviations and lookBack + +code:: +( +~loDev = -6; +~hiDev = 5; +~lookBack = 2; + +p = Pbind( + \dur, 0.2, + \midinote, PIdev(72, 11, Pfunc { ~loDev }, Pfunc { ~hiDev }, Pfunc { ~lookBack }).trace(prefix: "midi "), +).play; +) + +// change on the fly +// as lookBack equals 2, this defines a fixed sequence (up or down anyway) + +( +~loDev = -1; +~hiDev = 1; +) + +// widen range + +( +~loDev = -6; +~hiDev = 5; +) + +// force a twelve-tone row + +~lookBack = 11; + + +// contradictory input, lookBack 11 not possible within range, causes repetitions + +( +~loDev = -3; +~hiDev = 2; +) + +p.stop +:: + + + + +anchor::Ex.3:: +subsection::Ex. 3: Moving source signal + +code:: +( +~loDev = -1; +~hiDev = 1; +~lookBack = 2; + +p = Pbind( + \dur, 1/7, + \midinote, PIdev( + Pseg(Pseq([65, 90], inf), 5, \sin).round, + 11, + Pfunc { ~loDev }, + Pfunc { ~hiDev }, + Pfunc { ~lookBack } + ).trace(prefix: "midi "), +).play; +) + +// widen range and increase lookBack + +( +~loDev = -6; +~hiDev = 5; +~lookBack = 10; +) + +p.stop +:: + + + +anchor::Ex.4:: +subsection::Ex. 4: Dynamic deviation range and lookBack + +code:: +// lookBack and deviations coupled here +// maxLookBack must be large enough + +( +~loDev = -1; +~hiDev = 1; +~lookBack = 2; + + +p = Pbind( +    \dur, 1/7, +    \midinote, PIdev( +        78, +        10, +        Pn(Plazy { ~loDev }), +        Pn(Plazy { ~hiDev }).trace(prefix: "absolute deviation "), +        Pn(Plazy { ~lookBack }) +    ).trace(prefix: "midi "); +).play +) + +// start parameter movement on the fly + +( +~loDev = Pseg(Pseq([2, 5].neg, inf), 5, \sin); +~hiDev = Pseg(Pseq([2, 5], inf), 5, \sin).trace(prefix: "absolute deviation and lookBack "); +~lookBack = Pseg(Pseq([2, 5], inf), 5, \sin); +) + +p.stop +:: + + + + +anchor::Ex.5:: +subsection::Ex. 5: Non-integer source + +code:: +( +~loDev = -6; +~hiDev = 5; +~lookBack = 3; +~thr = 1; + +p = Pbind( + \dur, 1/7, + \midinote, PIdev( + Pseg(Pseq([65, 90], inf), 5, \sin), + 5, + Pfunc { ~loDev }, + Pfunc { ~hiDev }, + Pfunc { ~lookBack }, + Pfunc { ~thr } + ).trace(prefix: "midi "), +).play; +) + +// close floats can occur here +~thr = 0.01 + +// not here +~thr = 2 + +p.stop +:: + + + + +anchor::Ex.6:: +subsection::Ex. 6: Multichannel expansion + +code:: +// larger pitch range and lookBack in upper voice, +// as with most patterns, no automatic array expansion of pattern arguments + +( +p = Pbind( + \dur, 1/7, + \src, Pseg(Pseq([65, 85], inf), 5, \sin).round, + \midinote, Ptuple([ + PIdev(Pkey(\src), 1, -1, 1), + PIdev(Pkey(\src) + 8.5, 3, -5, 5) + ]).trace(prefix: "midi "), +).play; +) + +p.stop +:: + + + + +anchor::Ex.7:: +subsection::Ex. 7: Application to other params: rhythm + +code:: +// if we have indexed data of whatever, we can slide over it, +// groups of durations as items to be streamed by PIdev + +( +~rhythmBase = [ + [1, 1], + [2, 1, 1], + [1, 1, 2] +].collect(_.normalizeSum); + +~rhythms = ~rhythmBase *.x [1, 2]; +~rhythmNum = ~rhythms.size; +~rhythms = ~rhythms.scramble; + +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, + rq = 0.05, pan = 0, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, Pan2.ar(sig, pan)); +}).add; +) + +( +// rhythmic variation and partial pitch repetition +// play for a while to note slow sliding caused by Pseg + +~loDev = -1; +~hiDev = 1; + +p = Pbind( + \instrument, \noise_grain, + \rel, Pexprand(0.05, 0.15), + \dur, PIdev( + // be careful not to exceed index bounds + Pseg(Pseq([~loDev.abs, ~rhythmNum - ~hiDev - 1], inf), 10, \sin, inf).round, + 2, // lookBack span, no repetition within 3 items + ~loDev, + ~hiDev + ).trace(prefix: "rhythm type: ").collect(~rhythms[_]).flatten * 0.3, + \midinote, Pstutter(Pwhite(1, 2), Pclump(3, Pxrand((50..100), inf))).flatten + [0, 12], + \pan, Pstutter(Pwhite(1, 2), Pclump(3, Pwhite(-1.0, 1))).flatten +).play; +) + +p.stop +:: + + +anchor::Ex.8:: +subsection::Ex. 8: Proof of concept + +code:: +( +// Function to check an array for repetitions within a maximum test span + +~repetitionCheck = { |array, maxTestSpan| + maxTestSpan.do { |i| + var result = (array.drop(i+1) - array).drop((i+1).neg).includes(0).not; + ("no repetitions within a span of " ++ (i+2).asString ++ " items: ").post; + result.postln; + } +} +) + +// test case +// no repetitions within a maximum span of 6 (lookBack == 5) + +( +p = PIdev(Pbrown(0, 20, 0.3).round.asInteger, 5, -7, 7).iter; +a = p.nextN(10000); +a.plot; +~repetitionCheck.(a, 10); +) + +:: + diff --git a/HelpSource/Classes/PL.schelp b/HelpSource/Classes/PL.schelp new file mode 100644 index 0000000..2ac45d0 --- /dev/null +++ b/HelpSource/Classes/PL.schelp @@ -0,0 +1,144 @@ +CLASS:: PL +summary:: dynamic scope placeholder pattern +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Classes/PLn + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. +note:: PL follows a paradigm of immediate replacement. There are cases though where you might prefer to finish streams or substreams before replacement, especially when syncing comes into play, for these options consider link::Classes/PLn:: and the strong::cutItems:: arg of PLx list patterns. +:: + +CLASSMETHODS:: + +method::new + +Creates a new PL object. + +argument::item +Symbol or other Object. +If a Symbol is passed, item can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::type +Expects 1 or inf. +Defines how items other than Patterns or Streams should be embedded. +Defaults to 1. Rather to be used by other PLx Patterns than by the user. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +p = Pbind(\midinote, PL(\a), \dur, 0.2); + + +// prepare current Environment + +( +~a = 60; +x = p.play; +) + + +// replace with items or patterns + +~a = 58; + + +// PL had repeats = inf, so Pseq is embedded endlessly + +~a = Pseq([60, 60, 58, 60, 53, 54.5, 56, 58]); + +x.stop; + + +////////////////////// + + +// placeholder may also get event patterns + +( +p = PL(\a, 1); + +~a = Pbind( + \midinote, Pwhite(80, 85), + \dur, 0.2 +); + +x = p.play; +) + + + +// replace, PL had repeats = 1, so ... + +( +~a = Pbind( + \midinote, Pseq((70..65)), + \dur, 0.05 +); +) + + +////////////////////// + + +// PL may be used in cases where there is no PLx implementation + +// Pseg used for pitch curve, linear interpolation + +( +p = Pbind( + \midinote, Pseg(PL(\p), PL(\d), \lin, inf), + \dur, 0.1 +); + +~p = Pshuf((50..75)); + +~d = 0.2; + +x = p.play; +) + + +// play with segment length + +~d = 0.4; + +~d = 1; + + +// can also be replaced by pattern + +~d = Pseq([0.2, 0.4, 1]); + + +// only two points left for interpolation +// there may be repetitions + +~p = Pshufn([50, 100]).trace; + +x.stop; + + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLIdev.schelp b/HelpSource/Classes/PLIdev.schelp new file mode 100755 index 0000000..0e76b2f --- /dev/null +++ b/HelpSource/Classes/PLIdev.schelp @@ -0,0 +1,378 @@ +CLASS:: PLIdev +summary:: dynamic scope pattern searching for numbers with integer distance from a source pattern, optionally avoiding repetitions within a span +categories:: Libraries>miSCellaneous>Other patterns, Libraries>miSCellaneous>Idev suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/Idev_suite, Tutorials/PLx_suite, Classes/PIdev, Classes/DIdev + + +DESCRIPTION:: + + +DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples. + +note:: +It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples. +:: + +note:: +In contrast to DIdev, PIdev and PLIdev do *not* need to know maximum deviations (strong::minLoDev::, strong::maxHiDev::) beforehand. Thus the order of arguments is different (here strong::loDev:: and strong::hiDev:: before lookBack). +:: + + + +CLASSMETHODS:: + + +method::new + +Creates a new PLIdev object. + + +argument::pattern +Symbol or PIdev pattern arg. The source value pattern to start search from. If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. + +argument::maxLookBack +Integer, the maximum lookback span. Fixed, defaults to 3. + +argument::loDev +Symbol or PIdev loDev arg. Determines the current low deviation for the search. If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to -3. + +argument::hiDev +Symbol or PIdev hiDev arg. Determines the current high deviation for the search. If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 3. + +argument::lookBack +Symbol or PIdev lookBack arg. Determines the current lookback span for avoiding repetitions. Can be modulated but must not exceed strong::maxLookBack::. If no value is passed, then strong::maxLookBack:: is taken. If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to nil. + +argument::thr +Symbol or PIdev thr arg. Threshold for equality comparison. If a Symbol is passed, a pattern/value can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 1e-3. + +argument::length +Symbol or PIdev length arg. Number of repeats. If a Symbol is passed, a value can be assigned to an envir variable later on. Defaults to inf. + +argument::envir +Dictionary or one of the Symbols \top, \t (topEnvironment), \current, \c (currentEnvironment). Dictionary to be taken for variable reference. Defaults to \current. + + + +section::Examples + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + + +anchor::Ex.1:: +subsection::Ex. 1: Basic usage: random choice within region without repetitions + +code:: +// constant source, max deviation +/- 3 +// no repetition within 5 pitches + +( +~in = 72; + +p = Pbind( + \dur, 0.2, + \midinote, PLIdev(\in, 5, -3, 3).trace(prefix: "midi "), +).play; +) + +// change source + +~in = 65 + +p.stop +:: + + + + +anchor::Ex.2:: +subsection::Ex. 2: Variable deviations and lookBack + +code:: +( +~loDev = -6; +~hiDev = 5; +~lookBack = 2; + +p = Pbind( + \dur, 0.2, + \midinote, PLIdev(72, 11, \loDev, \hiDev, \lookBack).trace(prefix: "midi "), +).play; +) + + +// change on the fly +// as lookBack equals 2, this defines a fixed sequence (up or down anyway) + +( +~loDev = -1; +~hiDev = 1; +) + + +// widen range + +( +~loDev = -6; +~hiDev = 5; +) + + +// force a twelve-tone row + +~lookBack = 11; + + +// contradictory input, lookBack 11 not possible within range, causes repetitions + +( +~loDev = -3; +~hiDev = 2; +) + +p.stop +:: + + + + +anchor::Ex.3:: +subsection::Ex. 3: Moving source signal + +code:: +( +~loDev = -1; +~hiDev = 1; +~lookBack = 2; + +p = Pbind( + \dur, 1/7, + \midinote, PLIdev( + Pseg(Pseq([65, 90], inf), 5, \sin).round, + 11, + \loDev, + \hiDev, + \lookBack + ).trace(prefix: "midi "), +).play; +) + + +// widen range and increase lookBack + +( +~loDev = -6; +~hiDev = 5; +~lookBack = 10; +) + +p.stop +:: + + + +anchor::Ex.4:: +subsection::Ex. 4: Dynamic deviation range and lookBack + +code:: +// lookBack and deviations coupled here +// maxLookBack must be large enough + +( +~loDev = -1; +~hiDev = 1; +~lookBack = 2; + +p = Pbind( + \dur, 1/7, + \midinote, PLIdev(78, 10, \loDev, \hiDev, \lookBack).trace(prefix: "midi "), +).play; +) + +// start parameter movement on the fly + +( +~loDev = Pseg(Pseq([2, 5].neg, inf), 5, \sin); +~hiDev = Pseg(Pseq([2, 5], inf), 5, \sin).trace(prefix: "absolute deviation and lookBack "); +~lookBack = Pseg(Pseq([2, 5], inf), 5, \sin); +) + +p.stop +:: + + + + +anchor::Ex.5:: +subsection::Ex. 5: Non-integer source + +code:: +( +~loDev = -6; +~hiDev = 5; +~lookBack = 3; +~thr = 1; + +p = Pbind( + \dur, 1/7, + \midinote, PLIdev( + Pseg(Pseq([65, 90], inf), 5, \sin), + 5, + \loDev, + \hiDev, + \lookBack, + \thr + ).trace(prefix: "midi "), +).play; +) + + +// close floats can occur here +~thr = 0.01 + + +// not here +~thr = 2 + +p.stop +:: + + + + +anchor::Ex.6:: +subsection::Ex. 6: Multichannel expansion + +code:: +// larger pitch range and lookBack in upper voice +// as with most patterns, no automatic array expansion of pattern arguments + +( +~src = Pseg(Pseq([65, 85], inf), 5, \sin).round; + +p = Pbind( + \dur, 1/7, + \midinote, Ptuple([ + PLIdev(\src, 1, -1, 1), + PLIdev(\src, 3, -5, 5) + 8.5 + ]).trace(prefix: "midi "), +).play; +) + +p.stop +:: + + + + +anchor::Ex.7:: +subsection::Ex. 7: Application to other params: rhythm + +code:: +// if we have indexed data of whatever, we can slide over it, +// groups of durations as items to be streamed by PLIdev + +( +~rhythmBase = [ + [1, 1], + [2, 1, 1], + [1, 1, 2] +].collect(_.normalizeSum); + +~rhythms = ~rhythmBase *.x [1, 2]; +~rhythmNum = ~rhythms.size; +~rhythms = ~rhythms.scramble; + +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, + rq = 0.05, pan = 0, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, Pan2.ar(sig, pan)); +}).add; +) + +( +// rhythmic variation and partial pitch repetition +// play for a while to note slow sliding, caused by Pseg + +~loDev = -1; +~hiDev = 1; +~maxLookBack = 5; // fixed ! +~lookBack = 2; + +// be careful not to exceed index bounds +~src = Pseg(Pseq([~loDev.abs, ~rhythmNum - ~hiDev - 1], inf), 10, \sin, inf).round; + +p = Pbind( + \instrument, \noise_grain, + \rel, Pexprand(0.05, 0.15), + \dur, PLIdev(\src, ~maxLookBack, \loDev, \hiDev, \lookBack).trace(prefix: "rhythm type: ") + .collect(~rhythms[_]).flatten * 0.3, + \midinote, Pstutter(Pwhite(1, 2), Pclump(3, Pxrand((50..100), inf))).flatten + [0, 12], + \pan, Pstutter(Pwhite(1, 2), Pclump(3, Pwhite(-1.0, 1))).flatten +).play; +) + + +// more variation by larger deviation from fixed source and larger lookBack + +( +~src = 3; +~loDev = -3; +~hiDev = 2; +~lookBack = 4; +) + + +// fixed cycle with these bounds and lookBack == 1 + +( +~loDev = -1; +~hiDev = 0; +~lookBack = 1; +) + +// other fixed cycle + +~src = 2; + +p.stop +:: + + +anchor::Ex.8:: +subsection::Ex. 8: Proof of concept + +code:: +( +// Function to check an array for repetitions within a maximum test span + +~repetitionCheck = { |array, maxTestSpan| + maxTestSpan.do { |i| + var result = (array.drop(i+1) - array).drop((i+1).neg).includes(0).not; + ("no repetitions within a span of " ++ (i+2).asString ++ " items: ").post; + result.postln; + } +} +) + +// test case +// no repetitions within a maximum span of 6 (maxLookBack == 5) + +( +~src = Pbrown(0, 20, 0.3).round.asInteger; +p = PLIdev(\src, 5, -7, 7).iter; +a = p.nextN(10000); +a.plot; +~repetitionCheck.(a, 10); +) +:: + diff --git a/HelpSource/Classes/PLbeta.schelp b/HelpSource/Classes/PLbeta.schelp new file mode 100644 index 0000000..c6b4012 --- /dev/null +++ b/HelpSource/Classes/PLbeta.schelp @@ -0,0 +1,114 @@ +CLASS:: PLbeta +summary:: dynamic scope Pbeta variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pbeta, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLbeta object. + +argument::lo +Symbol or Pbeta lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Pbeta hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::prob1 +Symbol or Pbeta prob1 arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::prob2 +Symbol or Pbeta prob2 arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pbeta length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \midinote, PLbeta(\lo, \hi, \p1, \p2), + \dur, 0.1 +); +) + +// prepare current Environment +// prob values for equal distribution + +( +~lo = 60; +~hi = 90; +~p1 = 1; +~p2 = 1; +) + + +// run + +x = p.play; + + +// replace probabilities, get values close to the bounds + +( +~p1 = 0.02; +~p2 = 0.02; +) + + +// change between close-to-bounds and equally-distributed +// PLseq defaults to repeats = inf + +( +~p1 = Pstutter(10, PLseq([0.01, 1])); +~p2 = Pstutter(10, PLseq([0.01, 1])); +) + + +// moving bounds + +( +~lo = PLseq((60..70)); +~hi = PLseq((80..90)); +) + +x.stop; + +:: + diff --git a/HelpSource/Classes/PLbindef.schelp b/HelpSource/Classes/PLbindef.schelp new file mode 100755 index 0000000..2a2c71c --- /dev/null +++ b/HelpSource/Classes/PLbindef.schelp @@ -0,0 +1,423 @@ +CLASS::PLbindef +summary::wrapper for Pbindef which allows replacement in object prototyping style +categories:: Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Tutorials/PLx_suite, Classes/PLbindefPar, Classes/PLbindefEnvironment, Classes/PLbindefParEnvironment, Classes/EventShortcuts, Tutorials/PLx_and_live_coding_with_Strings + + +DESCRIPTION:: +PLbindef works like a normal Pbindef and, like the latter, uses Pdef's global bookkeeping, but replacement of key streams can be done in object prototyping style with a dedicated PLbindefEnvironment, which also holds player methods. This hybrid Environment is itself assigned to the PLbindef's name in an Environment of choice, by default the current Environment. Setting can thus be done in very condensed syntax, also in combination with link::Classes/EventShortcuts::. For more info on object prototyping see link::Classes/Environment#Using Environments as object prototypes#::. + + +note:: +PLbindefs are registered globally in the same Dictionary as Pdefs, Pbindefs and PLbindefPars. It's recommended to do cleanup with code::remove:: or code::Pdef.removeAll:: after using PLbindef / PLbindefPar as in examples below. Otherwise unwanted or strange behaviour might be caused by leftover sources when playing a new PLbindef / PLbindefPar example with the same key. With SC >= 3.7 occasional posts of the default parent event occur with Pbindef, so also with PLbindef, this doesn't cause problems though. +:: + +CLASSMETHODS:: + +method::new + +Creates a new PLbindef object or sets sources as with Pbindef. + +argument::... args +First arg should be the name, followed by key/value pairs for the Pbindef. The last arg can be an optional environment which determines where the corresponding PLbindefEnvironment should be stored, by default this is the current Environment at instantiation time. + +INSTANCEMETHODS:: + +private::miSC_setRefEnvir +private::miSC_updateSourceEnvir + + +method::clear + +As with link::Classes/Pdef#-clear::, but in addition remove name entry from strong::refEnvir::. + + +method::sourceEnvir + +Getter for PLbindef's PLbindefEnvironment. + + +method::refEnvir + +Getter for the Environment where PLbindef's PLbindefEnvironment is associated with PLbindef's key. + + + +anchor::above:: +SECTION::Examples + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +// synthdefs to play with + +( +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; +) +:: + + +SUBSECTION::Ex.1) Setting key streams + +code:: +// start with a fresh global Dictionary + +Pdef.removeAll + +// store PLbindef under key \x + +( +PLbindef(\x, + \instrument, \sin_grain, + \dur, 0.2, + \midinote, Pwhite(60, 90) +) +) + +// PLbindefEnvironment has been made and assigned to the variable ~x in currentEnvironment, check + +~x + + +// now the PLbindefEnvironment can also be treated as a player + +~x.play + + +// set params while playing + +~x.att = Pwhite(0.01, 0.2) + +~x.midinote = 75 + +~x.att = 0.01 + +~x.dur = 0.02 + +~x.midinote = Pbrown(60, 90, 1.5) + + +// prototype underscore syntax + +~x.midinote_(Pbrown(70, 80, 3)) + + + +// pause + +~x.stop + +// resume + +~x.play + + + +// use method 'value' for parallel setting + +~x.(\dur, 0.05, \midinote, Pwhite(70.0, 72)) + + +// sequential underscore setting + +~x.dur_(0.07).midinote_(Pwhite(72.0, 74)) + + +// Pbindef syntax of setting also still possible + +PLbindef(\x, \dur, 0.1, \midinote, Pwhite(80, 81.0)) + + +~x.stop + +// cleanup + +~x.remove +:: + + + +SUBSECTION::Ex.2) PLbindef with EventShortcuts + +Use SynthDefs from link::Classes/PLbindef#above#above::. + +code:: +// syntax can be more condensed with EventShortcuts, turn it on, post defaults + +EventShortcuts.on + +EventShortcuts.postCurrent + + +( +PLbindef(\u, + \i, \saw_grain, + \d, 0.2, + \m, Pwhite(60, 90) +) +) + +~u.play + +~u.d = 0.1 + + +~u.m = Pn(Plazy { Pseries(rrand(50, 70), 1.5, 20) }) + +~u.m = ~u.m + [0, 4, 7] + +~u.i = PLseq([\sin_grain, \saw_grain]) + + +~u.a = Pn(Pseries(0.05, 0.01, 20)) + +~u.m = 70 + + +// stop + cleanup in one + +~u.remove +:: + + + +SUBSECTION::Ex.3) PLbindef with VarGui + +Use SynthDef from link::Classes/PLbindef#above#above::. + +code:: +// start with gui and define pitch sequence with sliders + +( +p = PLbindef(\z, + \i, \saw_grain, + \d, 0.2, + \m, PLseq(\midi) +); + +VarGui([\midi, [50, 90, \lin, 1, 60] ! 7], stream: p).gui; +) + + +~z.m = PLseq(\midi) + [0, 5, 8] + +~z.m = ~z.m + PLseq([-1, 0, 1] * 12) + +// stop with gui, then do cleanup + +~z.remove +:: + + +SUBSECTION::Ex.4) PLbindef with PbindFx + +See also link::Classes/PbindFx#Ex. 7c#Ex.7c: Replacement with Pbindef:: + +code:: +// boot server with extended resources + +( +s.options.numPrivateAudioBusChannels = 1024; +s.options.memSize = 8192 * 16; +s.reboot; +) + +( +SynthDef(\echo, { |out, in, maxEchoDelta = 0.2, echoDelta = 0.1, + decayTime = 1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = DelayL.ar( + CombL.ar(inSig, maxEchoDelta, echoDelta, decayTime, amp), + maxEchoDelta, + maxEchoDelta - echoDelta + ); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000, + cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = RLPF.ar( + inSig, + LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi), + rq, + amp + ).softclip; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; +) + +// prepare EventShortcuts for additional keys + +( +EventShortcuts.addOnBase(\default, \fxs, ( + dec: \decayTime, + cd: \cleanupDelay, + cf: \cutOffMoveFreq, + fxo: \fxOrder, + dta: \echoDelta +), true); + +EventShortcuts.makeCurrent(\fxs); + +EventShortcuts.on; +) + + +( +// source and fxs passed as PLbindefs + +k = [\q, \echo, \wah]; + +PLbindef(\q, + \i, PLrand([\noise_grain, \saw_grain]), + \d, 0.25, + \m, PLseq([60, 60, 60, 62]), + \fxo, PLseq([0, 0, 1, 2]), + // echo introduces delay, so do delay if no echo + \lag, Pfunc { |e| e.fxo.asArray.includes(1).if { 0 }{ 0.2 } }, + \a, 0.1, + \att, 0.01, + \rel, 0.1, + + \cd, Pkey(\att)+ Pkey(\rel) + 0.001 +); + +PLbindef(\echo, + \fx, \echo, + \dta, 0.06, + \a, 0.5, + \dec, Pwhite(0.3, 1.8), + \cd, Pkey(\dec) +); + +PLbindef(\wah, + \fx, \wah, + \cf, Pwhite(1, 3), + \a, 0.5, + \cd, 0.01 +); + + +p = PbindFx(*k.collect(PLbindef(_))); // PbindFx(*(k.collect { |x| PLbindef(x) })); + +q = p.play; +) + + + +// manipulate midinotes + +~q.m = ~q.m + PLseq([0, 12, -12]) + +~q.m = ~q.m + PLrand([0, [0, -4]]) + +~q.m = ~q.m + PLrand([0, [0, -7]]) + + +// rhythm + +~q.d = PLshufn([1, 1, 2, 1] / 8) + + +// echo param and fx order sequence + +~echo.dta = Pwhite(0.03, 0.08) + +~q.fxo = PLseq([0, 0, 1, 2, 1, [1, 2]]) + + + +~q.m = 48 + +// produce overtone series with echodelta + +~echo.dta = 1 / 24.midicps / PLseq((1..16)) + + +// this also works in chords ("fx expansion") +// source is processed twice per event + +~echo.dta = 1 / [24, 26.7].midicps / PLseq((1..16)) + + + +// cleanup + +q.stop + +Pdef.removeAll +:: + + + + + +SUBSECTION::Ex.5) Passing a refEnvir + +code:: +// on occasion it might be desirable to control from a dedicated Environment + +Pdef.removeAll + +( +PLbindef(\a, + \instrument, \sin_grain, + \dur, 0.2, + \midinote, Pwhite(60, 90), + e = () +) +) + +e.use { ~a.play } + +e[\a].stop + +e.a.play + +e.a.stop + +e.a.remove +:: diff --git a/HelpSource/Classes/PLbindefEnvironment.schelp b/HelpSource/Classes/PLbindefEnvironment.schelp new file mode 100644 index 0000000..e97c5b3 --- /dev/null +++ b/HelpSource/Classes/PLbindefEnvironment.schelp @@ -0,0 +1,82 @@ +CLASS::PLbindefEnvironment +summary::Environment made by PLbindef to play and set its sources +categories:: Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Tutorials/PLx_suite, Classes/PLbindef, Classes/PLbindefPar, Classes/PLbindefParEnvironment, Classes/EventShortcuts, Tutorials/PLx_and_live_coding_with_Strings + + +DESCRIPTION:: +Instances of this class are made as side effect of PLbindef creation, assigned to PLbindef's name in an Environment of choice (by default the current one) and used as player interface as well as for setting PLbindef's sources in condensed prototyping syntax. They are not thought to be created explicitely though. See link::Classes/PLbindef:: for examples. + + + +CLASSMETHODS:: + +method::new + +Creates a new PLbindefEnvironment object with arguments of IdentityDictionary. In contrast to the latter strong::know:: defaults to true, which allows setting sources of the PLbindef in object prototyping style. strong::name:: is used for the corresponding key of the PLbindef. Normally not to be used explicitely. + + +INSTANCEMETHODS:: + +private::miSC_setName +private::miSC_envirClear +private::miSC_setPLbindef + +method::put + +Associates strong::obj:: with Symbol strong::key:: and updates PLbindef's source. + + +method::superPut + +Associates strong::obj:: with Symbol strong::key:: mimicing link::Classes/IdentityDictionary#-put::. + + +method::value + +Expects key/value pairs and applies strong::put::. + + +method::name + +Getter for PLbindef's key. + + +method::plbindef + +Getter for the corrresponding PLbindef. + + +method::play + +Plays all corresponding PLbindefs with passed arguments, which might be arrays. In this case wrapped indexing is applied. + + +method::isPlaying + +Indicates if the corresponding PLbindef is playing. + + +method::reset + +Resets the corresponding PLbindef. + + +method::stop + +Stops the corresponding PLbindef. + + +method::clear + +Clears the corresponding PLbindef. + + +method::remove + +Removes the corresponding PLbindef. + + + + + diff --git a/HelpSource/Classes/PLbindefPar.schelp b/HelpSource/Classes/PLbindefPar.schelp new file mode 100755 index 0000000..8072697 --- /dev/null +++ b/HelpSource/Classes/PLbindefPar.schelp @@ -0,0 +1,672 @@ +CLASS::PLbindefPar +summary::container for parallel PLbindefs which allows replacement in object prototyping style +categories:: Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite + +related:: Overviews/miSCellaneous, Tutorials/PLx_suite, Classes/PLbindef, Classes/PLbindefEnvironment, Classes/PLbindefParEnvironment, Classes/EventShortcuts, Tutorials/PLx_and_live_coding_with_Strings + + +DESCRIPTION:: +PLbindefPar employs a number of parallel PLbindefs, replacement of key streams can be done in object prototyping style with a dedicated PLbindefParEnvironment, which also holds player methods. This hybrid Environment is itself assigned to the PLbindefPar's name in an Environment of choice, by default the current Environment. Setting can thus be done in very condensed syntax, also in combination with link::Classes/EventShortcuts::. For more info on object prototyping see link::Classes/Environment#Using Environments as object prototypes#::. + +note:: +PLbindefs are registered globally in the same Dictionary as Pdefs, Pbindefs and PLbindefPars. In addition for size = n PLbindefs of the same name with indices i = 0, ... n-1 appended are stored globally. It's recommended to do cleanup with code::remove:: or code::Pdef.removeAll:: after using PLbindef / PLbindefPar as in examples below. Otherwise unwanted or strange behaviour might be caused by leftover sources when playing a new PLbindef / PLbindefPar example with the same key. With SC >= 3.7 occasional posts of the default parent event occur with Pbindef, so also with PLbindef, this doesn't cause problems though. +:: + +note:: +For setting, getting, playing, stopping and resetting subsets of PLbindefs in prototyping syntax the class TempPLbindefParEnvironment is involved (see link::Classes/PLbindefPar#Ex. 1#Ex.1::). The user doesn't need to care about this class, instances are generated implicitely and might occur in the post window. +:: + + + +CLASSMETHODS:: + +method::new + +Creates a new PLbindefPar object or sets sources of an existing one. + + +argument::... args +First arg should be the strong::name::, followed by strong::num::, the number of parallel PLbindefs, and the key/value pairs. Values are assigned to single PLbindefs according to the convention of link::Classes/PLbindefParEnvironment#-put::, see there and examples below. The last arg can be an optional environment which determines where the corresponding PLbindefParEnvironment should be stored, by default this is the current Environment at instantiation time. + +INSTANCEMETHODS:: + +private::miSC_setRefEnvir +private::miSC_updateSourceEnvir +private::eventShortcuts + + +method::sourceEnvir + +Getter for PLbindefPar's PLbindefParEnvironment. + + +method::refEnvir + +Getter for the Environment where PLbindefPar's PLbindefParEnvironment is associated with PLbindefPar's key. + + +method::num + +Getter for PLbindefPar's number of parallel PLbindefs. + + +method::play + +Plays all corresponding PLbindefs with passed arguments, which might be arrays. In this case wrapped indexing is applied. + + +method::reset + +Resets all corresponding PLbindefs. + + +method::stop + +Stops all corresponding PLbindefs. + + + +method::clear + +Clears all corresponding PLbindefs. + + +method::remove + +Removes not only the PLbindefPar but also associated PLbindefs from global entry. + + +method::subPLbindefs + +Returns corresponding PLbindefs. + + +method::subEnvirs + +Returns corresponding PLbindefEnvironments. + + + +anchor::above:: +SECTION::Examples + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +// synthdefs to play with + +( +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +EventShortcuts.on; +) + +:: + +anchor::Ex. 1:: +SUBSECTION::Ex.1) Setting key streams + +code:: +// start with a fresh global Dictionary + +Pdef.removeAll + +// use with EventShortcuts + +EventShortcuts.on + +( +PLbindefPar(\v, 3, + \i, [\saw_grain, \sin_grain, \noise_grain], + \d, 0.8, + \m, [65, 70, 80], + \rq, 0.002, + \a, 0.03, + \att, Pwhite(0.05, 0.01) +) +) + +// now we have a PLbindefEnvironment as player which can use indices + +~v.play + + +// set all streams to one val or pattern + +~v.d = PLseq([0.2, 0.1, 0.1]) + + +// set all streams to different vals or patterns + +~v.d = [0.1, 0.3, PLseq([0.2, 0.1])] + + +// set single streams + +~v[2].d = PLseq([0.2, 0.2, 0.1]) + +~v[2].m = Pwhite(90, 100) + + + +// set only some streams + +~v[[0, 1]].m = [67, 77] + +~v[[1, 2]].m = [Pwhite(75, 80.0), 92] + + + +// parallel intervals and chords for single streams + +~v[2].m = Pwhite(80, 90) + [0, 9] + +~v[0].m = Pwhite(50, 65) + [0, 5] + +~v[1].m = Pwhite(70, 75.5) + [0, 3, 7] + + +~v.m = [72, 76, 79] + +~v.m = Pwhite(0.0, 1) ! 3 + [72, 76, 79] + + +// this is different: +// all PLbindefs get the same pattern with chord +// WARNING: with large arrays this can become loud! + +~v.m = Pwhite(0.0, 2) + [72, 76, 79] + + +// reference to last sources + +~v.m = [72, 76, 79 + PLseq([1, 2])] + +~v.m = ~v.m + 1.5 + +~v.m = ~v.m + [0, -12, 12] + +~v[2].m = ~v[2].m - 5 + + +// subarray reference to last sources + +~v[[1, 2]].m = ~v[[1, 2]].m - 7 + + +// equivalent, here getter looks different as not from temporary envir: + +// ~v[[1, 2]].m = ~v.m[[1, 2]] - 7 + + + +// use adverbs to build chords on each voice + +~v.m = ~v.m +.t [0, 4, 7] + + +// pause single streams + +~v[1].stop + +~v[2].stop + + +// play all again + +~v.play + + +// can also be done this way + +PLbindefPar(\v).stop + +PLbindefPar(\v).play + + +
// stop, start and reset substreams + +~v[[0, 1]].stop + +~v[[0, 1]].play + + + +// set more than one key, all streams + +~v.(\d, 0.1, \m, [70, 75, 80 + Pwhite(0.0, 5)]) + + +// set more than one key, but only chosen streams + +~v.([0, 2], \d, [0.35, 0.5], \m, [90, 97]) + + +// this can still be done similar to Pbindef-style + +PLbindefPar(\v, [0, 2], \d, [0.3, 0.55], \m, [83, 86]) + + +// prototyping's underscore syntax, applied successively + +~v.d_([0.4, 0.5, 0.6]).m_([70, 81, 92]) + +~v[1].d_(0.15).m_(94) + +~v[[0, 2]].d_(0.25).m_([73, 77.5]) + + + +// set all streams, they might be time-shifted + +~v.d = 0.2 + + +// hard sync with reset + +~v.reset + +~v.stop + + +// with method 'play' arrays can be passed to clock, protoType, quants and doReset + +~v.play([1, 1.05, 1.1].collect(TempoClock(_))) + +~v.stop + + +// wrapped indexing applies, same clock for players 0 and 2 + +~v.play([1, 1.5].collect(TempoClock(_))) + + +// stop + cleanup + +~v.remove +:: + + + +anchor::Ex. 2:: +SUBSECTION::Ex.2) More parallel streams, from granular to additive + +Use SynthDefs from link::Classes/PLbindefPar#above#above::. + +code:: +// use EventShortcuts + +EventShortcuts.on + +( +PLbindefPar(\y, 12, + // wrapped indexing: collection is used for all 12 streams + \i, [\saw_grain, \sin_grain, \noise_grain], + \d, (1..12)/100, + \m, { rrand(60, 90) } ! 12, + \a, 0.02, + \rq, 0.002 +) +) + +~y.play + +// evaluate more than once + +~y.m = { rrand(60, 90) } ! 12 + + +// refer to current midinotes + +~y.m = ~y.m - 1 + + +~y.d = [1, 2, 4] / 8 + +~y.d = ~y.d / 4 + +~y.stop + +~y.remove + + + +// replacement introducing additive structures + +( +PLbindefPar(\add, 12, + \i, \sin_grain, + \d, 1, + \m, { Pn(Pseries(rrand(40, 60), Pwhite(1.0, 3), 20)) } ! 12, + \att, 5, + \rel, 5, + \a, 0.005 +).play +) + +~add.f = { PLseq((1..16)) * (100 + Pwhite(0.0, 3)) } ! 12 + +~add.stop + +~add.remove +:: + + +anchor::Ex. 3:: +SUBSECTION::Ex.3) PLbindefPar with VarGui + +Use SynthDefs from link::Classes/PLbindefPar#above#above::. + +code:: +// PLbindefPar's single streams can be prepared for VarGui +// start with gui and define pitch sequences with sliders + +( +EventShortcuts.on; + +p = PLbindefPar(\w, 3, + \i, [\saw_grain, \sin_grain, \noise_grain], + \d, [1, 2, 4] / 8, + \n, PLseq(\midi), + \m, 70 + Pkey(\n), + \a, 0.05, + \rq, 0.001 +); + +VarGui([\midi, [0, 12, \lin, 1, 0] ! 4] ! 3, stream: p.subPLbindefs, quant: 1).gui +) + + +~w.d = [4, 2, 1] / 8 + +~w.d = [1, 2, PLrand([2, 2, 1])] / 8 + + +// lines or chords per layer + +~w.m = [70, 75, 80].collect(Pkey(\n) + _) // ~w.m = [70, 75, 80].collect { |i| Pkey(\n) + i } + +~w.m = Pkey(\n) + [70, 75, 80] + + +// exchange instruments + +~w.i = ~w.i.reverse + + +// exchange some durations + +~w[[0, 1]].d = [0.5, 0.8] + + +// stop with gui + +// cleanup after stopping with gui + +~w.remove +:: + + + +anchor::Ex. 4:: +SUBSECTION::Ex.4) PLbindefPar with PbindFx + +See also link::Classes/PbindFx#Ex. 7c#Ex.7c: Replacement with Pbindef:: + +code:: +// boot server with extended resources + +( +s.options.numPrivateAudioBusChannels = 1024; +s.options.memSize = 8192 * 16; +s.reboot; + +// fx synths + +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\echo, { |out, in, maxEchoDelta = 0.2, echoDelta = 0.1, + decayTime = 1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = DelayL.ar( + CombL.ar(inSig, maxEchoDelta, echoDelta, decayTime, amp), + maxEchoDelta, + maxEchoDelta - echoDelta + ); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000, + cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = RLPF.ar( + inSig, + LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi), + rq, + amp + ).softclip; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + + +// prepare EventShortcuts for additional keys + +EventShortcuts.addOnBase(\default, \fxs, ( + dec: \decayTime, + cd: \cleanupDelay, + cf: \cutOffMoveFreq, + fxo: \fxOrder, + dta: \echoDelta +), true); + +EventShortcuts.makeCurrent(\fxs); + +EventShortcuts.on; +) + + +( +// source and fxs passed as PLbindefPar / PLbindefs + +PLbindefPar(\r, 12, + \i, [\noise_grain, \saw_grain], + \d, 0.25, + \m, PLseq([60, 60, 60, 62]), + \fxo, PLseq([0, 0, 1, 2]), + // echo introduces delay, so do delay if no echo + \lag, Pfunc { |e| e.fxo.asArray.includes(1).if { 0 }{ 0.2 } }, + \a, 0.03, + \att, 0.01, + \rel, 0.1, + + \cd, Pkey(\att) + Pkey(\rel) + 0.001 +); + +PLbindef(\echo, + \fx, \echo, + \dta, 0.06, + \a, 1, + \dec, Pwhite(0.3, 1.8), + \cd, Pkey(\dec) +); + +PLbindef(\wah, + \fx, \wah, + \cf, Pwhite(1, 3), + \a, 1, + \cd, 0.01 +); + + +// we rather take a Ppar of PbindFxs than a PbindFx with a Ppar source + +q = Ppar( + PLbindefPar(\r).subPLbindefs.collect { |plbindef| + PbindFx(plbindef, PLbindef(\echo), PLbindef(\wah)) + } +).play +) + +
// still single source streams can be controlled by the PLbindefPar interface +// differentiate rhythm + +~r.d = (1..12) / 8 + + + +// manipulate midinotes + +~r.m = (48, 50..70) + + +// echo param and fx order sequence + +~echo.dta = Pwhite(0.03, 0.08) + +~r.fxo = PLseq([0, 0, 1, 2, 1, [1, 2]]) + + + +// produce overtone series with echodelta + +~echo.dta = 1 / 24.midicps / PLseq((1..16)) + + +// this also works in chords ("fx expansion") +// source is processed twice per event + +~echo.dta = 1 / [24, 26.7].midicps / PLseq((1..32).mirror) + + +// cleanup + +q.stop + +Pdef.removeAll +:: + + +anchor::Ex. 5:: +SUBSECTION::Ex.5) PLbindefPar with array args + +code:: +// specific bracketing needed here in analogy to array args with Pbinds + +( +SynthDef(\noise_grain_chord, { |out = 0, freq = #[400, 500], att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin_grain_chord, { |out = 0, freq = #[400, 500], att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\saw_grain_chord, { |out = 0, freq = #[400, 500], att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +EventShortcuts.on +) + +( +PLbindefPar(\c, 3, + \i, [\saw_grain_chord, \noise_grain_chord, \sin_grain_chord], + \d, 0.5, + \rq, 0.02, + \m, [[70, 79]] ! 3, + // or: [[[70, 79]]] + + // this looks a bit weird, but it's necessary: + // with Pbind and array args we need double bracketing, + // here we are refering to an array of Pbind data + \a, 0.03, + \att, Pwhite(0.02, 0.01), + \rel, 0.2 +); + +~c.play +) + + +~c.m = [[[75, 78]]] + + +// set single streams + +~c[1].d = 0.3; + +~c[2].d = 0.4; + + + +~c[0].m = [[65, 68]] + +~c[2].m = [[87, 90]] + + +// set substreams + +~c[[0, 1]].m = [[[65, 70]] + Pseq([0, 1.5], inf), [[75, 80]]] + +( +~c.([1, 2], + \d, [0.6, 0.35], + \m, [ + [[75, 80]] + Pseq([0, 1], inf), + [[85, 90]] + Pseq([0, 1.5, 2.5], inf) + ] +) +) + +~c.remove +:: + + diff --git a/HelpSource/Classes/PLbindefParEnvironment.schelp b/HelpSource/Classes/PLbindefParEnvironment.schelp new file mode 100644 index 0000000..f09a964 --- /dev/null +++ b/HelpSource/Classes/PLbindefParEnvironment.schelp @@ -0,0 +1,98 @@ +CLASS::PLbindefParEnvironment +summary::Environment made by PLbindefPar to play and set its sources +categories:: Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Tutorials/PLx_suite, Classes/PLbindef, Classes/PLbindefPar, Classes/PLbindefEnvironment, Classes/EventShortcuts, Tutorials/PLx_and_live_coding_with_Strings + + +DESCRIPTION:: +Instances of this class are made as side effect of PLbindefPar creation, assigned to PLbindefPar's name in an Environment of choice (by default the current one) and used as player interface and to set PLbindef's sources in condensed syntax. They are not thought to be created explicitely though. +A PLbindefParEnvironment contains the references to its PLbindefs as Associations of indices to PLbindefEnvironments. See link::Classes/PLbindefPar:: for examples. + +note:: +For setting, getting, playing, stopping and resetting subsets of PLbindefs in prototyping syntax the class TempPLbindefParEnvironment is involved (see link::Classes/PLbindefPar#Ex. 1#Ex.1:: in PLbindefPar's help). The user doesn't need to care about this class, instances are generated implicitely and might occur in the post window. +:: + +CLASSMETHODS:: + +method::new + +Creates a new PLbindefParEnvironment object with arguments of IdentityDictionary. In contrast to the latter strong::know:: defaults to true, which allows setting sources of the PLbindefPar in object prototyping style. strong::name:: is used for the corresponding key of the PLbindefPar. strong::num:: is the number of parallel patterns in the PLbindefPar. strong::plbindefPar:: is the corresponding PLbindefPar, strong::plbindefs:: might be passed. Normally not be used explicitely. + + +INSTANCEMETHODS:: + +private::miSC_setNum +private::miSC_setName +private::miSC_setPLbindef +private::miSC_plbindefParInit + +method::put + +Associates strong::obj:: with Symbol strong::key:: and updates the stored PLbindefEnvironments depending on the class of strong::obj::. For a SequenceableCollection items are assigned in the PLbindefEnvironments of corresponding indices (method 'wrapAt' is used for handling cases of smaller collections). Other types of passed objects are assigned in all PLbindefEnvironments. + + +method::superPut + +Associates strong::obj:: with Symbol strong::key:: mimicing link::Classes/IdentityDictionary#-put::. + + +method::value + +Expects key/value pairs and applies strong::put::. Optionally the first arg can be an Integer or a collection of Integers, specifying the PLbindefs to be set. + + +method::num + +Getter for PLbindefPar's number of parallel PLbindefs. + + +method::name + +Getter for PLbindefPar's key. + + +method::plbindefPar + +Getter for the corrresponding PLbindefPar. + + +method::at + +For Integers it works as link::Classes/IdentityDictionary#-at::, for SequenceableCollections of Integers it enables setting and getting as well as playing, stopping, resetting and clearing of sources of corresponding PLbindefs by using a TempPLbindefParEnvironment (see link::Classes/PLbindefPar#Ex. 1#Ex.1:: in PLbindefPar's help). + + +method::play + +Plays all PLbindefs of the corresponding PLbindefPar with passed arguments. + + +method::reset + +Resets all PLbindefs of the corresponding PLbindefPar. + + +method::stop + +Stops all PLbindefs of the corresponding PLbindefPar. + + +method::clear + +Clears all PLbindefs of the corresponding PLbindefPar and delete references to sourceEnvir and refEnvir. + + +method::remove + +Removes the corresponding PLbindefPar and all related PLbindefs from the global entry, delete references to sourceEnvir and refEnvir. + + +method::subPLbindefs + +Returns corresponding PLbindefs. + + +method::subEnvirs + +Returns corresponding PLbindefEnvironments. + + diff --git a/HelpSource/Classes/PLbrown.schelp b/HelpSource/Classes/PLbrown.schelp new file mode 100644 index 0000000..22ce25b --- /dev/null +++ b/HelpSource/Classes/PLbrown.schelp @@ -0,0 +1,88 @@ +CLASS:: PLbrown +summary:: dynamic scope Pbrown variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pbrown, Classes/PLgbrown, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLbrown object. + +argument::lo +Symbol or Pbrown lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Pbrown hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::step +Symbol or Pbrown step arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0.125. + +argument::length +Symbol or Pbrown length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +p = PLbrown(\lo, \hi, \step); + + +// prepare current Environment +// PLseq repeats arg defaults to inf + +( +~lo = 55; +~hi = 80; +~step = Pstutter(10, PLseq([0.05, 3.5])); +) + + +// run + +( +x = Pbind( + \midinote, Ptuple(p!2), + \dur, 0.1 +).play; +) + +// replace + +( +~lo = Pseq((50..90)); +~hi = Pseq((50..90) + 15); +) + +:: + diff --git a/HelpSource/Classes/PLcauchy.schelp b/HelpSource/Classes/PLcauchy.schelp new file mode 100644 index 0000000..9e00be6 --- /dev/null +++ b/HelpSource/Classes/PLcauchy.schelp @@ -0,0 +1,86 @@ +CLASS:: PLcauchy +summary:: dynamic scope Pcauchy variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pcauchy, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLcauchy object. + +argument::mean +Symbol or Pcauchy mean arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::spread +Symbol or Pcauchy spread arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pcauchy length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments, +// Cauchy distribution is not bounded, so do clip ! + +( +p = Pbind( + \midinote, PLcauchy(\mean, \spread).clip(60, 90), + \dur, 0.1 +); +) + +// prepare current Environment + +( +~mean = 75; +~spread = 0.1; +) + + +// run + +x = p.play; + + +// move mean value and distribution +// PLseq defaults to repeats = inf + +( +~mean = PLseq((80, 79.7..70)); +~spread = PLseq([0, 0, 0, 1]); +) + +x.stop; + +:: + diff --git a/HelpSource/Classes/PLexprand.schelp b/HelpSource/Classes/PLexprand.schelp new file mode 100644 index 0000000..5e435a3 --- /dev/null +++ b/HelpSource/Classes/PLexprand.schelp @@ -0,0 +1,85 @@ +CLASS:: PLexprand +summary:: dynamic scope Pexprand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pexprand, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLexprand object. + +argument::lo +Symbol or Pexprand lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0.0001. + +argument::hi +Symbol or Pexprand hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pexprand length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments, +// intervals grow together with base tone + +( +q = PLexprand(\lo, \hi); + +p = Pbind( + \midinote, 60 + q + PLtuple([0, q]), + \dur, 0.1 +); +) + + +// prepare current Environment + +( +~lo = 0.1; +~hi = 10; +) + + +// run + +x = p.play; + + +// replace + +~hi = 20; + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLgauss.schelp b/HelpSource/Classes/PLgauss.schelp new file mode 100644 index 0000000..0257219 --- /dev/null +++ b/HelpSource/Classes/PLgauss.schelp @@ -0,0 +1,86 @@ +CLASS:: PLgauss +summary:: dynamic scope Pgauss variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pgauss, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLgauss object. + +argument::mean +Symbol or Pgauss mean arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::dev +Symbol or Pgauss dev arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pgauss length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments, +// Gauss distribution is not bounded, so do clip ! + +( +p = Pbind( + \midinote, PLgauss(\mean, \dev).clip(60, 90), + \dur, 0.1 +); +) + +// prepare current Environment + +( +~mean = 75; +~dev = 0.3; +) + + +// run + +x = p.play; + + +// move mean value and distribution +// PLseq defaults to repeats = inf + +( +~mean = PLseq((80, 79.75..70.25)); +~dev = Pstutter(8, PLseq([4, 0])); +) + +x.stop; + +:: + diff --git a/HelpSource/Classes/PLgbrown.schelp b/HelpSource/Classes/PLgbrown.schelp new file mode 100644 index 0000000..ac3b346 --- /dev/null +++ b/HelpSource/Classes/PLgbrown.schelp @@ -0,0 +1,97 @@ +CLASS:: PLgbrown +summary:: dynamic scope Pgbrown variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pgbrown, Classes/PLbrown, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLgbrown object. + +argument::lo +Symbol or Pgbrown lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Pgbrown hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::step +Symbol or Pgbrown step arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0.125. + +argument::length +Symbol or Pgbrown length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \midinote, PLgbrown(\lo, \hi, \step) + [0, -7.4, -12.7], + \dur, 0.1, + \amp, 0.05 +); +) + +// prepare Environments + +( +e = (lo: 65, hi: 90, step: 0.01); +f = e.copy.put(\step, 0.05); +) + + +// run + +( +e.use { x = p.play(quant: 0.2) }; +f.use { y = p.play(quant: 0.2) }; +) + +// replace + +( +e.lo = 65; +f.lo = 65; +e.hi = Pwhite(65, 67); +f.hi = Pwhite(65, 95); +f.step = 0.3 +) + +y.stop; + +x.stop; + +:: + diff --git a/HelpSource/Classes/PLgeom.schelp b/HelpSource/Classes/PLgeom.schelp new file mode 100644 index 0000000..8661f7e --- /dev/null +++ b/HelpSource/Classes/PLgeom.schelp @@ -0,0 +1,85 @@ +CLASS:: PLgeom +summary:: dynamic scope Pgeom variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pgeom, Classes/PLseries, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLgeom object. + +argument::start +Symbol or Pgeom start arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to 0. + +argument::grow +Symbol or Pgeom grow arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pgeom length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \freq, Pn(PLgeom(\start, \grow, 50)) % 2000 + 400, + \dur, 0.1 +); +) + +// prepare current Environment + +( +~start = 100; +~grow = 1.1; +) + + +// from ascending to random + +x = p.play; + + +// replace + +~grow = 0.99; + +~grow = 1.4; + + +x.stop; + + +:: + diff --git a/HelpSource/Classes/PLhprand.schelp b/HelpSource/Classes/PLhprand.schelp new file mode 100644 index 0000000..b22a9d3 --- /dev/null +++ b/HelpSource/Classes/PLhprand.schelp @@ -0,0 +1,90 @@ +CLASS:: PLhprand +summary:: dynamic scope Phprand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Phprand, Classes/PLlprand, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLhprand object. + +argument::lo +Symbol or Phprand lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Phprand hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Phprand length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +q = PLhprand(\lo, \hi); + + +// prepare current Environment +// PLseq repeats arg defaults to inf + +( +~lo = 60; +~hi = PLseq((92..62)); +) + + + +// run + +( +y = Pbind( + \midinote, Ptuple(q!5), + \dur, 0.1, + \amp, 0.05 +).play; +) + + +// replace, converging bounds + +( +~lo = PLseq((40..70) ++ (70!5)); +~hi = 70.5; +) + +y.stop; + + +:: + +Compare this example with lo-weighted link::Classes/PLlprand:: diff --git a/HelpSource/Classes/PLlprand.schelp b/HelpSource/Classes/PLlprand.schelp new file mode 100644 index 0000000..f4a1d73 --- /dev/null +++ b/HelpSource/Classes/PLlprand.schelp @@ -0,0 +1,91 @@ +CLASS::PLlprand +summary::dynamic scope Plprand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Plprand, Classes/PLhprand, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLlprand object. + +argument::lo +Symbol or Plprand lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Plprand hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Plprand length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +p = PLlprand(\lo, \hi); + + +// prepare current Environment +// PLseq repeats arg defaults to inf + +( +~lo = 60; +~hi = PLseq((92..62)); +) + + +// run + +( +x = Pbind( + \midinote, Ptuple(p!5), + \dur, 0.1, + \amp, 0.05 +).play; +) + + +// replace, converging bounds + +( +~lo = PLseq((40..70) ++ (70!5)); +~hi = 70.5; +) + +x.stop; + +:: + +Compare this example with hi-weighted link::Classes/PLhprand:: + + + \ No newline at end of file diff --git a/HelpSource/Classes/PLmeanrand.schelp b/HelpSource/Classes/PLmeanrand.schelp new file mode 100644 index 0000000..b88ba92 --- /dev/null +++ b/HelpSource/Classes/PLmeanrand.schelp @@ -0,0 +1,87 @@ +CLASS:: PLmeanrand +summary:: dynamic scope Pmeanrand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pmeanrand, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLmeanrand object. + +argument::lo +Symbol or Pmeanrand lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Pmeanrand hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pmeanrand length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +p = PLmeanrand(\lo, \hi); + + +// prepare current Environment +// PLseq repeats arg defaults to inf + +( +~lo = PLseq((60, 60.25..70)); +~hi = PLseq((70, 69.75..60)); +) + + +// run + +( +x = Pbind( + \midinote, Ptuple([p, 65]), + \amp, [0.1, 0.06], + \dur, 0.1 +).play; +) + + +// replace + +( +~lo = 60.5; +~hi = 61; +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLn.schelp b/HelpSource/Classes/PLn.schelp new file mode 100644 index 0000000..9b27ceb --- /dev/null +++ b/HelpSource/Classes/PLn.schelp @@ -0,0 +1,219 @@ +CLASS:: PLn +summary:: dynamic scope placeholder pattern whose streams will be finished before replacements +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Classes/PL + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. In contrast to link::Classes/PL:: a replacement doesn't take effect immediately, but with the next embedding. This behaviour might be preferred with syncing. +note:: +As sources are finished before next replacements are possible, infinite source streams, other than with other PLx patterns, inhibit further replacements at all. For the option of finishing substreams with PLx list patterns see their cutItems arg and link::#Ex.3::. +:: + +CLASSMETHODS:: + +method::new + +Creates a new PL object. + +argument::item +Symbol or other Object. +If a Symbol is passed, item can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +anchor::Ex.1:: +subsection::Ex.1: Protection of periods + +code:: + +// compare PL and PLn, start with polling two items from each Stream +// Note that Pseq defaults to repeats = 1 and PL/PLn default to repeats = inf + +( +~a = Pseq([1, 2, 3]); +x = PLn(\a).asStream; +y = PL(\a).asStream; + +x.nextN(2); +y.nextN(2); +) + + +// replace proxy source + +~a = ~a * 100; + + +// Stream from PLn finishes before replacement + +x.nextN(2) + +// With PL substream is replaced immediately + +y.nextN(2) +:: + + +anchor::Ex.2:: +subsection::Ex.2: Protection of periods for syncing + + +code:: + +// playing two interval lines in parallel + +( +~a = Pseq([4, 2, 0]) + [0, -5]; +~b = Pseq([7, 5, 4]) + [0, 5]; + +p = Pbind( + \dur, Pseq([0.4, 0.2, 0.2], inf), + \note, PLn(\a) +); + +q = Pbindf(p, \note, PLn(\b)); + +x = Ppar([p, q]).play; +) + + + +// replace the lower event stream, new notes start after end of embedding Pseq + +~a = Pseq([3, 2, 0]) + [0, -5]; + + +// replace second line + +~b = Pseq([7, 5, 4]) + [5, 12]; + + +// source nil stops event stream after end of embedding Pseq + +~a = nil; +:: + + +anchor::Ex.3:: +subsection::Ex.3: Protection of periods and subperiods with event streams + +code:: + +// define two Pbinds of same length, play first + +( +x = Pbind( + \dur, Pseq([0.4, 0.2, 0.2]), + \note, Pseq([4, 2, 0]) +); + +y = Pbind( + \dur, 0.2, + \note, Pseq([7, 7, 5, 4]) +); + +~a = x; + +PLn(\a).play; +) + +// switch between them several times, periods are protected + +~a = y; + +~a = x; + + +// define a sequence of parts, we want to exchange parts later on + +( +~trill_1 = Pbind( + \dur, 0.4/3, + \note, Pseq([7, 9, 7]) +); + +~trill_2 = Pbind( + \dur, 0.4/5, + \note, Pseq([7, 8, 7, 8, 7]) +); + +~fin = Pbind( + \dur, 0.2, + \note, Pseq([5, 4]) +); + +~b = [~trill_1, ~fin]; +) + +// replace with a PLseq +// note that source must have repeats = 1, +// in order to protect substreams with PLseq and change the behaviour later on +// we pass to cutItmes a Function that, for now, returns false + +( +~cutItems = false; +~a = PLseq(\b, 1, cutItems: \cutItems); + +~b[0] = ~trill_2; +) + +// helper function to generate trill patterns + +~trill = { |lo, hi, dur, reps| Pbind(\dur, dur / reps, \note, Pser([lo, hi], reps)) }; + + +// replace with a long slow trill + +~b[0] = ~trill_3 = ~trill.(7, 9, 0.9, 5); + + + +// replace back while long trill, +// due to the current value ~cutItems = false it will be completed and +// replacement takes effect in next loop + +~b[0] = ~trill_2; + +// replace back + +~b[0] = ~trill_3; + + +// change replacing behaviour + +~cutItems = true; + + +// now replacing while long trill will take immediate effect + +~b[0] = ~trill_2; + + +// stop + +~a = nil + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLnaryFunc.schelp b/HelpSource/Classes/PLnaryFunc.schelp new file mode 100755 index 0000000..ac61674 --- /dev/null +++ b/HelpSource/Classes/PLnaryFunc.schelp @@ -0,0 +1,90 @@ +CLASS:: PLnaryFunc +summary:: dynamic scope PnaryFunc variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pnaryop, Classes/PLnaryop, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. For replacing operators dynamically take link::Classes/PLnaryFunc:: with the operator wrapped into a Function. + + +CLASSMETHODS:: + +method::new + +Creates a new PLnaryFunc object. + +argument::func +Symbol or func arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by a Pattern or Stream. + +argument::pat +Symbol or pattern arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. + +argument::arglist +They are starting with input for the Function's second arg, +as items from pat will be passed to its first. +If Symbols are passed, arglist args can be assigned to envir variables later on. +Can be dynamically replaced by Patterns or Streams. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \midinote, PLnaryFunc(\f, \src, [\dev]), + \dur, 0.1 +); +) + + +// define Environment and play + +( +e = (f: { |x,y| x + y }, src: PLseq([61, 62]), dev: Pbrown(-5, 5, 0.2) ); + +e.use { x = p.play }; +) + + +// replace Function input Patterns + +e.dev = PLseq((0, 0.5..7)); + +e.src = PLseq([61,64,65]); + + +// replace Function + +e.f = { |x,y| x - y }; + +e.f = { |x,y| y * 4 + x }; + + +x.stop; + +:: + +See also link::Tutorials/PLx_suite#Ex. 5b#Ex.5b::. \ No newline at end of file diff --git a/HelpSource/Classes/PLnaryop.schelp b/HelpSource/Classes/PLnaryop.schelp new file mode 100755 index 0000000..685ee41 --- /dev/null +++ b/HelpSource/Classes/PLnaryop.schelp @@ -0,0 +1,82 @@ +CLASS:: PLnaryop +summary:: dynamic scope Pnaryop variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pnaryop, Classes/PLnaryFunc, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. For replacing operators dynamically take link::Classes/PLnaryFunc:: with the operator wrapped into a Function. + + +CLASSMETHODS:: + +method::new + +Creates a new PLnaryop object. + +argument::operator +Symbol or Pnaryop operator arg. +If a Symbol is passed, list can be assigned to an envir variable later on. + +argument::pat +Symbol or Pnaryop pattern arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. + +argument::arglist +Symbols or Pnaryop arglist arg. +If Symbols are passed, arglist args can be assigned to envir variables later on. +Can be dynamically replaced by Patterns or Streams. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \midinote, PLnaryop('+', \src, [\dev]), + \dur, 0.1 +); +) + + +// define Environment and play + +( +e = (src: PLseq([61,62]), dev: Pbrown(-5, 5, 0.2) ); + +e.use { x = p.play }; +) + + +// replace + +e.dev = PLseq((0, 0.5..7)); + +e.dev = Pbrown(-5, 5, 0.2); + +e.src = PLseq([61,64,65]); + + +x.stop; +:: + +link::Tutorials/PLx_suite#Ex. 5a#Ex.5a::. \ No newline at end of file diff --git a/HelpSource/Classes/PLpoisson.schelp b/HelpSource/Classes/PLpoisson.schelp new file mode 100644 index 0000000..d56be5b --- /dev/null +++ b/HelpSource/Classes/PLpoisson.schelp @@ -0,0 +1,75 @@ +CLASS:: PLpoisson +summary:: dynamic scope Ppoisson variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Ppoisson, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLpoisson object. + +argument::mean +Symbol or Ppoisson mean arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Ppoisson length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments, +// Poisson distribution gives positive integer values + +( +p = Pbind( + \midinote, (PLpoisson(\mean) + 50).clip(60, 90), + \dur, 0.1 +); +) + + +// prepare current Environment + +~mean = 10; + + +// run + +x = p.play; + + +// changing mean value + +~mean = Pstutter(5, PLseq((0, 5..30))); + +x.stop; + +:: + diff --git a/HelpSource/Classes/PLrand.schelp b/HelpSource/Classes/PLrand.schelp new file mode 100644 index 0000000..b71e094 --- /dev/null +++ b/HelpSource/Classes/PLrand.schelp @@ -0,0 +1,139 @@ +CLASS:: PLrand +summary:: dynamic scope Prand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Prand, Classes/PLxrand, Classes/PLwrand, Classes/PLshuf, Classes/PLshufn, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLrand object. + +argument::list +Symbol or Prand list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Prand repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// define Pattern and prepare Environments + +( +p = Pbind( + \midinote, PLrand(\a), + \dur, 0.2 +); + +e = (a: (67..72)); +f = (a: (77..82)); +) + +// start together or not, but sync anyway + +e.use { x = p.play(quant: 0.2) }; +f.use { y = p.play(quant: 0.2) }; + + +// replace array elements ... + +f.a[0] = 97; + +e.a[0] = 96; + + +// ... or arrays + +f.a = (72, 72.5..77); + +e.a = [60]; + +e.a = [Pseq([60, 47.5]) + [0, 5], [61, 65.5]]; + +x.stop; +y.stop; + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLrand(\a); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.2 + ) +]; + +x = p.play; +) + + +// replace array element + +( +~a[0] = Pbind( + \midinote, Pwhite(70, 75, 3) + [0, 5], + \dur, 0.15 +); +) + + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.05 + ), + Pbind( + \midinote, Pwhite(70, 90, 2), + \dur, 0.25 + ) +]; +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLseq.schelp b/HelpSource/Classes/PLseq.schelp new file mode 100755 index 0000000..f58816c --- /dev/null +++ b/HelpSource/Classes/PLseq.schelp @@ -0,0 +1,137 @@ +CLASS:: PLseq +summary:: dynamic scope Pseq variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pseq, Classes/PLser, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLseq object. + +argument::list +Symbol or Pseq list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Pseq repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::offset +Symbol or Pseq offset arg. Defaults to 0. +If a Symbol is passed, offset can be assigned to an envir variable later on. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \midinote, PLseq(\a), + \dur, 0.1 +); +) + + +// assign a value to variable ~a in current Environment, +// play there. +// PLseq defaults to repeats = inf, Pseq defaults to repeats = 1 + +( +~a = (67..70) ++ Pseq((99..70)); + +x = p.play; +) + + +// try replacing Pseq stream while chromatic line down, +// works immediately with default value cutItems = true + +~a[4] = 73; + + +// replace whole list + +~a = (60..65); + +x.stop; + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLseq(\a); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.2 + ) +]; + +x = p.play; +) + + +// replace array element + +( +~a[0] = Pbind( + \midinote, Pwhite(70, 75, 3) + [0, 5], + \dur, 0.15 +); +) + +// replace whole array + +( +~a = [ Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.05 + ), + Pbind( + \midinote, Pwhite(70, 90, 2), + \dur, 0.25 + ) +]; +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLser.schelp b/HelpSource/Classes/PLser.schelp new file mode 100644 index 0000000..62b220d --- /dev/null +++ b/HelpSource/Classes/PLser.schelp @@ -0,0 +1,115 @@ +CLASS:: PLser +summary:: dynamic scope Pser variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pser, Classes/PLseq, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLser object. + +argument::list +Symbol or Pser list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Pser repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::offset +Symbol or Pser offset arg. Defaults to 0. +If a Symbol is passed, offset can be assigned to an envir variable later on. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +// PLseq not used as proxy, only taken as it defaults to repeats = inf + +p = Pbind( + \midinote, PLseq([PLser(\a, \r), 60, 61]), + \dur, 0.2 +); + +// prepare current Environment + +~a = (67..70); +~r = 6; +) + +x = p.play; + + +// replace repeats + +~r = 3; + + +// replace array elements + +~a[0] = [77, 93.5]; + +~a[2] = Pseq((94..96)); + + +// replace whole array + +~a = [55, 52]; + +x.stop; + + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLser(\a, 3); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.1 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.1 + ) +]; + +x = p.play; +) + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLseries.schelp b/HelpSource/Classes/PLseries.schelp new file mode 100644 index 0000000..b33f1ea --- /dev/null +++ b/HelpSource/Classes/PLseries.schelp @@ -0,0 +1,92 @@ +CLASS:: PLseries +summary:: dynamic scope Pseries variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pseries, Classes/PLgeom, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLseries object. + +argument::start +Symbol or Pseries start arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to 0. + +argument::step +Symbol or Pseries step arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pseries length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +( +p = Pbind( + \midinote, PLseries(0, \step) % 24 + 60, + \dur, 0.1 +); +) + +// prepare Environments + +( +e = (step: 1); +f = e.copy; +) + + +// run + + +e.use { x = p.play(quant: 0.1) }; + +f.use { y = p.play(quant: 0.1) }; + + +// replace + +f.step = 2; + +e.step = Pwhite(0.5, 1.5); + +f.step = Pwhite(1, -3); + + + +y.stop; + +x.stop; + +:: + diff --git a/HelpSource/Classes/PLshuf.schelp b/HelpSource/Classes/PLshuf.schelp new file mode 100644 index 0000000..21cd648 --- /dev/null +++ b/HelpSource/Classes/PLshuf.schelp @@ -0,0 +1,138 @@ +CLASS:: PLshuf +summary:: dynamic scope Pshuf variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pshuf, Classes/Pshufn, Classes/PLshufn, Classes/PLrand, Classes/PLxrand, Classes/PLwrand, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. A PLshuf stream keeps a permutation until it ends or there is a list replacement. See link::Classes/PLshufn:: for ongoing choice of new permutations. + + +CLASSMETHODS:: + +method::new + +Creates a new PLshuf object. + +argument::list +Symbol or Pshuf list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Pshuf repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +p = Pbind( + \midinote, PLshuf(\a), + \dur, 0.2 +); + +// prepare Environment + +~a = (67..72); +) + +x = p.play; + + +// replace array elements ... + +~a[0] = 63; + + +// ... or whole arrays +// evaluating more than once gives a newly chosen permutation + +~a = (60..65); + +x.stop; + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLshuf(\a); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 6), + \dur, 0.1 + ) +]; + +x = p.play; +) + + +// replace array element + +( +~a[2] = Pbind( + \midinote, Pwhite(70, 75, 3) + [0, 5], + \dur, 0.15 +); +) + + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3) + [0, 5], + \dur, 0.15 + ), + Pbind( + \midinote, Pwhite(70, 80, 2) + [0, 4], + \dur, 0.25 + ), + Pbind( + \midinote, Pwhite(95, 100, 6) + [0, -9], + \dur, 0.05 + ) +]; +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLshufn.schelp b/HelpSource/Classes/PLshufn.schelp new file mode 100644 index 0000000..1a20176 --- /dev/null +++ b/HelpSource/Classes/PLshufn.schelp @@ -0,0 +1,145 @@ +CLASS:: PLshufn +summary:: dynamic scope Pshufn variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pshufn, Classes/Pshuf, Classes/PLshuf, Classes/PLrand, Classes/PLxrand, Classes/PLwrand, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. A PLshufn stream keeps on choosing permutations for the current list. See link::Classes/PLshuf:: for keeping one permutation. + + +CLASSMETHODS:: + +method::new + +Creates a new PLshufn object. + +argument::list +Symbol or Pshufn list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Pshufn repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +p = Pbind( + \midinote, PLshufn(\a), + \dur, 0.2 +); + +// prepare Environments + +e = (a: (67..72)); +f = (a: (77..82)); +) + +e.use { x = p.play(quant: 0.2) }; +f.use { y = p.play(quant: 0.2) }; + + +// replace array elements ... + +e.a[0] = 97; +f.a[0] = 98; + + +// ... or arrays + +( +e.a = [80, 81]; +f.a = (70..73); +) + +e.a[0] = Pwhite(60, 65, 1) + [0, -5, 29.5]; + +y.stop; +x.stop; + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLshufn(\a); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 6), + \dur, 0.1 + ) +]; + +x = p.play; +) + + +// replace array element + +( +~a[2] = Pbind( + \midinote, Pwhite(70, 75, 3) + [0, 5], + \dur, 0.15 +); +) + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3) + [0, 5], + \dur, 0.15 + ), + Pbind( + \midinote, Pwhite(70, 80, 2) + [0, 4], + \dur, 0.25 + ), + Pbind( + \midinote, Pwhite(95, 100, 6) + [0, -9], + \dur, 0.05 + ) +]; +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLslide.schelp b/HelpSource/Classes/PLslide.schelp new file mode 100644 index 0000000..5249ccf --- /dev/null +++ b/HelpSource/Classes/PLslide.schelp @@ -0,0 +1,158 @@ +CLASS:: PLslide +summary:: dynamic scope Pslide variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pslide, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLslide object. + +argument::list +Symbol or Pslide list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Pslide repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::len +Symbol or Pslide len arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 3. + +argument::step +Symbol or Pslide step arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::start +Symbol or Pslide start arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to 0. + +argument::wrapAtEnd +Symbol or Pslide wrapAtEnd arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to true. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +p = PLslide(\a, inf, \len, \step, \start); + + +// prepare current Environment + +( +~len = 3; +~step = 1; +~start = 0; +~a = [60, 61, 62, 70, 71, 72, 80, 81, 82]; +) + + +// run + +( +x = Pbind( + \midinote, p, + \dur, 0.2 +).play; +) + + +// replace list elements + +~a[0] = 60.5; + +~a[8] = Pseq([92, 80.5], 1); + + + +// len and step can be replaced by Patterns +// PLseq defaults to repeats = inf + +~len = Pstutter(5, PLseq([1, 2, 3])); + +( +~len = 1; +~step = Pstutter(2, PLseq([0, 4])); +) + +x.stop; + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLslide(\a, inf, \len, \step, \start); + +~len = 3; +~step = 1; +~start = 0; +~add = 0; + +~a = (60, 62..70).collect { |x| + Pbind( + \midinote, x + Pseq((0, 0.2..0.8)) + PL(\add), + \dur, 0.1 + ); +}; + +x = p.play; +) + + +// replace slide params an ~add + +~add = [4, 9]; + +~step = 2; + +~len = 4; + +~add = [4, 9, 13]; + + + +// replace array element + +( +~a[0] = Pbind( + \midinote, 80 + Pseq((0.8, 0.6..0)) + PL(\add), + \dur, 0.05 +); +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLswitch.schelp b/HelpSource/Classes/PLswitch.schelp new file mode 100644 index 0000000..dab83b4 --- /dev/null +++ b/HelpSource/Classes/PLswitch.schelp @@ -0,0 +1,162 @@ +CLASS:: PLswitch +summary:: dynamic scope Pswitch variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pswitch, Classes/PLswitch1, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLswitch object. + +argument::list +Symbol or Pswitch list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::which +Symbol or Pswitch which arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +p = PLswitch(\a, \w); + + +// define array +// PLseq defaults to repeats = inf + + +( +~a = (70..75) ++ Pshuf((85..80), 2) ++ Pseq((90..94)); + +~w = PLseq((0..7)); + +x = Pbind(\midinote, p, \dur, 0.1).play; +) + +// update array element + +~a[2] = Pseq([86, 85], 2) + [0,3]; + + +// reverse index pattern + +~w = PLseq((7..0)); + + +// keep in mind that indices are wrapped, no surprise here ... + +~a = (70,72..84); + + +// ... but with shorter array indices are grouped in 5 + 3 + +~a = (70,72..78); + +x.stop; + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLswitch(\a, \w); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(70, 75, 3), + \dur, 0.15 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.1 + ), + Pbind( + \midinote, Pwhite(90, 95, 6), + \dur, 0.05 + ) +]; + +~w = PLseq((0..3)); + +x = p.play; +) + + +// replace index sequence + +~w = PLseq([3,0]); + +~w = PLseq([1,2]); + + +// replace array element + +( +~a[2] = Pbind( + \midinote, Pwhite(70, 75, 3) + [0, 5], + \dur, 0.15 +); +) + + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3) + [0, 5], + \dur, 0.15 + ), + Pbind( + \midinote, Pwhite(70, 80, 2) + [0, 4], + \dur, 0.25 + ), + Pbind( + \midinote, Pwhite(95, 100, 6) + [0, -9], + \dur, 0.05 + ) +]; +) + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLswitch1.schelp b/HelpSource/Classes/PLswitch1.schelp new file mode 100644 index 0000000..33ed873 --- /dev/null +++ b/HelpSource/Classes/PLswitch1.schelp @@ -0,0 +1,163 @@ +CLASS:: PLswitch1 +summary:: dynamic scope Pswitch1 variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pswitch1, Classes/PLswitch, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLswitch1 object. + +argument::list +Symbol or Pswitch1 list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::which +Symbol or Pswitch1 which arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +p = PLswitch1(\a, \w); + + +// run Pbind in current Environment +// take PLseq as they already default to repeats = inf + +( +~a = [PLseq((85..80)), PLseq((65..70))]; +~w = PLseq([0, 1]); + +x = Pbind(\midinote, p, \dur, 0.1).play; +) + +// update array element + +~a[1] = PLseq([96, 95]); + + +// update array + +~a = [59, 85]; + + +// update index pattern, used to stop also + +~w = Pseq([0, 0, 1], 5); + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLswitch1(\a, \w); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(70, 75), + \dur, 0.15 + ), + Pbind( + \midinote, Pwhite(80, 85), + \dur, 0.1 + ), + Pbind( + \midinote, Pwhite(90, 95), + \dur, 0.05 + ) +]; + +~w = PLseq((0..3)); + +x = p.play; +) + + +// replace index sequence + +~w = PLseq([3, 0]); + +~w = PLseq([1, 2]); + + +// replace array element + +( +~a[2] = Pbind( + \midinote, Pwhite(70, 75) + [0, 5], + \dur, 0.15 +); +) + + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pwhite(60, 65) + [0, 5], + \dur, 0.15 + ), + Pbind( + \midinote, Pwhite(70, 80) + [0, 4], + \dur, 0.25 + ), + Pbind( + \midinote, Pwhite(95, 100) + [0, -9], + \dur, 0.05 + ), + Pbind( + \midinote, Pwhite(95, 100) + [0, -14], + \dur, 0.02 + ) +]; +) + +~w = PLshuf((0..3)); + +~w = PLshufn((0..3)); + + +x.stop; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLtuple.schelp b/HelpSource/Classes/PLtuple.schelp new file mode 100644 index 0000000..aedb930 --- /dev/null +++ b/HelpSource/Classes/PLtuple.schelp @@ -0,0 +1,94 @@ +CLASS:: PLtuple +summary:: dynamic scope Ptuple variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Ptuple, Classes/PLser, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLtuple object. + +argument::list +Symbol or Ptuple list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Ptuple repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +p = PLtuple(\a); + + +// prepare current Environment +// PLtuple defaults to repeats = inf, +// so inner Patterns are repeatedly embedded + +~a = [ Pshuf((60..65)), 70, Pshuf((75..80)) ]; + + +// run + +x = Pbind(\midinote, p, \dur, 0.2).trace.play; + + +// replace elements + +~a[0] = 72.5; + +~a[1] = 74.5; + +~a[2] = Prand([85, 86, 87]); + + +// replace array + +// Ptuple and PLtuple start with new embedding of ALL patterns +// if one ends, so here default repeats = inf of PLshuf has no effect: +// new permutation with every loop as Pshuf has repeats = 1 + +~a = [ Pshuf((60..65)), 70, PLshuf((75..80)) ]; + + +// both Patterns have repeats = inf, +// permutation is kept + +~a = [ PLshuf((60..65)), 70, PLshuf((75..80)) ]; + + +x.stop; +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLwalk.schelp b/HelpSource/Classes/PLwalk.schelp new file mode 100644 index 0000000..f4e213c --- /dev/null +++ b/HelpSource/Classes/PLwalk.schelp @@ -0,0 +1,186 @@ +CLASS:: PLwalk +summary:: dynamic scope Pwalk variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pwalk, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLwalk object. + +argument::list +Symbol or Pwalk list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::step +Symbol or Pwalk stepPattern arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to Prand([1, -1], inf). + +argument::direction +Symbol or Pwalk directionPattern arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::start +Symbol or Pwalk startPos arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// definition for future reference in arbitrary Environments + +p = PLwalk(\a, \step, \dir, \start); + + +// prepare current Environment + +( +~a = (60, 64..102); +~step = 1; +~start = 70; +~dir = -1; +) + + +// run + +( +x = Pbind( + \midinote, p + [0, 3], + \dur, 0.1, + \legato, 1.2 +).play; +) + + +// replace with Patterns +// PLx ListPatterns default to repeats = inf + +~step = PLrand([1, 2]); + +~dir = PLseq([-1, 1]); + + +// replace list + +~a = ~a - 1.5; + + +x.stop; + + + + +////////////////////// + + +// placeholder may also get lists of event patterns + + +( +p = PLwalk(\a, \step, \dir); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 1) + [0, -8.7], + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(70, 75, 2) + [0, -3.3], + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 90, 3) + [0, -4.3], + \dur, 0.1 + ), + Pbind( + \midinote, Pwhite(90, 100, 2) + [0, 5.7], + \dur, 0.05 + ) +]; + +~step = 1; + +~dir = 1; + +x = p.play; +) + + +// replace step pattern, pending between two source patterns +// try evaluating several times + +~step = PLseq([1, -1]); + +~step = 1; + + +// replace array element + +( +~step = 1; + +~a[0] = Pbind( + \midinote, Pwhite(60,75,1) + [0, 5, 14, 19, 22], + \dur, 0.15 +); + +~a[3] = Pbind( + \midinote, Pseq((90..95)), + \dur, 0.05 +); +) + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.05 + ), + Pbind( + \midinote, Pwhite(70, 90, 2), + \dur, 0.25 + ), + Pbind( + \midinote, Pwhite(70, 75, 3), + \dur, 0.05 + ), + Pbind( + \midinote, Pwhite(80, 95, 3) + [0, -5.3], + \dur, 0.3 + ) +]; +) + +x.stop; +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLwhite.schelp b/HelpSource/Classes/PLwhite.schelp new file mode 100644 index 0000000..2b2b9c1 --- /dev/null +++ b/HelpSource/Classes/PLwhite.schelp @@ -0,0 +1,84 @@ +CLASS:: PLwhite +summary:: dynamic scope Pwhite variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pwhite, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLwhite object. + +argument::lo +Symbol or Pwhite lo arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 0. + +argument::hi +Symbol or Pwhite hi arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. Defaults to 1. + +argument::length +Symbol or Pwhite length arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +Defaults to inf. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// definition for future reference in arbitrary Environments + +p = PLwhite(\lo, \hi); + + +// prepare current Environment +// PLseq repeats defaults to inf + +( +~lo = PLseq((60..70)); +~hi = PLseq((62..72)); +) + + +// run + +( +x = Pbind( + \midinote, p, + \dur, 0.1 +).play; +) + + +// replace, converging bounds, stops when ~lo ends (Pseq default repeats = 1) + +( +~lo = Pseq((60..80) ++ (80!5)); +~hi = 80; +) + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLwrand.schelp b/HelpSource/Classes/PLwrand.schelp new file mode 100644 index 0000000..43a0952 --- /dev/null +++ b/HelpSource/Classes/PLwrand.schelp @@ -0,0 +1,103 @@ +CLASS:: PLwrand +summary:: dynamic scope Pwrand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pwrand, Classes/PLrand, Classes/PLxrand, Classes/PLshuf, Classes/PLshufn, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLwrand object. + +argument::list +Symbol or Pwrand list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::weights +Symbol or Pwrand weights arg. +If a Symbol is passed, weights can be assigned to an envir variable later on. +Can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Pwrand repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +p = Pbind( + \freq, 50 * PLwrand(\a, \w), + \dur, 0.01, + \amp, 0.02 +); + +// prepare (current) Environment +// give low overtones more weight + +~a = (1..8); +~w = (8..1).cubed.normalizeSum; +) + +x = p.play; + + +// reverse overtone weights + +~w = (1..8).cubed.normalizeSum; + + +// replace with Pattern for weights, +// PLseq taken as repeats defaults to inf + +~w = Pstutter(50, PLseq([(8..1), (1..8)].collect { |x| x.cubed.normalizeSum })); + + +// replace arrays (must be sufficiently long) + +~a = (3..10); +~a = (5..12); + +~a = (1,3..15); +~a = (1,4..22); +~a = (1,5..29); +~a = (1,6..36); +~a = (2,7..37); +~a = (3,8..38); +~a = (4,9..39); +~a = (5,10..40); + +x.stop; + + + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PLxrand.schelp b/HelpSource/Classes/PLxrand.schelp new file mode 100644 index 0000000..7b573a7 --- /dev/null +++ b/HelpSource/Classes/PLxrand.schelp @@ -0,0 +1,150 @@ +CLASS:: PLxrand +summary:: dynamic scope Pxrand variant +categories::Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events>PLx suite +related:: Overviews/miSCellaneous, Classes/Pxrand, Classes/PLrand, Classes/PLwrand, Classes/PLshuf, Classes/PLshufn, Tutorials/PLx_suite, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds + + +DESCRIPTION:: + + +Takes Symbol args for later reference by the Streams, which will read from variables in the Environments of their instantiation. See link::Tutorials/PLx_suite::. + + +CLASSMETHODS:: + +method::new + +Creates a new PLxrand object. + +argument::list +Symbol or Pxrand list arg. +If a Symbol is passed, list can be assigned to an envir variable later on. +This lists's elements can be dynamically replaced by Patterns or Streams. + +argument::repeats +Symbol or Prand repeats arg. If a Symbol is passed, repeats can be assigned to an envir variable later on. Defaults to inf. + +argument::cutItems +Symbol or Boolean or Integer (0 or 1) or a Function returning Boolean or Integer. +If a Symbol is passed, cutItems can be assigned to an envir variable later on. +Determines if list items, which are Patterns or Streams themselves, +will be finished if a replacement occurs during their embedding, or if they will be replaced immediately. +The latter is the default behaviour (default value true). +For protecting whole lists from immediate replacements see link::Classes/PLn::. + +argument::envir +Dictionary or one of the Symbols +\top, \t (topEnvironment), \current, \c (currentEnvironment). +Dictionary to be taken for variable reference. Defaults to \current. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// define Pattern and prepare Environments + +( +p = Pbind( + \midinote, PLxrand(\a), + \dur, 0.2 +); + +e = (a: (67..72)); +f = (a: (73..78)); +) + +// start together or not, but sync anyway + +e.use { x = p.play(quant: 0.2) }; +f.use { y = p.play(quant: 0.2) }; + + +// replace array elements ... + +f.a[0] = Pseq((0, 0.5..3) + 75); + +e.a[0] = Pseq(60 - (0, 0.5..3)); + + +// ... or arrays + +f.a = (72, 72.5..77); + +e.a = [60]; + +e.a = [Pseq([60, 47.5]) + [0, 5], [61, 65.5], [80, 83.5]]; + +x.stop; +y.stop; + + + +////////////////////// + + +// placeholder may also get lists of event patterns + +( +p = PLxrand(\a); + +~a = [ + Pbind( + \midinote, Pwhite(60, 65, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(70, 75, 3), + \dur, 0.2 + ), + Pbind( + \midinote, Pwhite(80, 85, 3), + \dur, 0.2 + ) +]; + +x = p.play; +) + + +// replace array element + +( +~a[0] = Pbind( + \midinote, Pwhite(70, 75, 3) + [0, 5], + \dur, 0.15 +); +) + + +// replace whole array + +( +~a = [ + Pbind( + \midinote, Pxrand((60..65), 3), + \dur, 0.15 + ), + Pbind( + \midinote, Pxrand((85..95), 3), + \dur, 0.05 + ), + Pbind( + \midinote, Pxrand((70..80), 2), + \dur, 0.25 + ) +]; +) + +x.stop; + +:: + + + \ No newline at end of file diff --git a/HelpSource/Classes/PS.schelp b/HelpSource/Classes/PS.schelp new file mode 100644 index 0000000..1ca3170 --- /dev/null +++ b/HelpSource/Classes/PS.schelp @@ -0,0 +1,251 @@ +CLASS:: PS +summary:: Pattern that behaves like a Stream +categories::Libraries>miSCellaneous>PSx stream patterns, Streams-Patterns-Events>PSx stream patterns +related:: Overviews/miSCellaneous, Tutorials/PSx_stream_patterns, Classes/MemoRoutine, Classes/PSdup, Classes/PSrecur, Classes/PSloop + + +DESCRIPTION:: + + +In general Patterns are stateless. But e.g. for counted embedding in other Patterns the exception of stream-like behaviour is practical. PS might also be used in cases where Streams must not be passed to certain Patterns. + +note:: +Name and implementation of former Pstream has changed with miSCellaneous_v0.9, in compliance with other PSx patterns it's been renamed to PS / PStream, however for backwards compatibility Pstream will still work by subclassing. + +:: + + +CLASSMETHODS:: + +method::new + +Creates a new PS object. + +argument::srcPat +Source pattern, might also be event pattern. + +argument::length +Number of output items, may be pattern or stream, defaults to inf. + +argument::bufSize +Size of buffer to store last values, defaults to 1. + +argument::copyItems +Determines if and how to copy items, which are which are either non-Sets or member of Sets. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). +Other values are interpreted as 0. Defaults to 0. + +0: original item + +1: copy item + +2: deepCopy item + +argument::copySets +Determines if to copy Sets (and hence Events). +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). +Other values are interpreted as 0. Defaults to 1. + +0: original Set + +1: copy Set + +note:: +The distinction of copying items and sets makes sense in the case of event streams. Per default Events are copied (strong::copySets:: == 1), not their values (strong::copyItems:: == 0). By playing Events those are used to store additional data (synth ids, msgFuncs …) which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use MemoRoutine - copied Events will not contain this additional data. If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured then copying makes no sense, this is the normal case, so copyItems defaults to 0. When going to alter the ouput, you might want to set strong::copyItems:: to 1 for a PSx returning simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set strong::copySets:: to 1 and strong::copyItems:: to 2 (an option strong::copySets:: == 2 doesn't exist as it would be contradictory in combination with strong::copyItems:: < 2). +:: + + +note:: +Copy options concern copying into PS's buffer as well as the output of a Stream derived from the PS. When such a Stream is outputting copies this prevents unintended altering of items from strong::srcPat::. On the other hand storing copies in PS's buffer prevents these from being altered unintendedly. +:: + + +INSTANCEMETHODS:: + +method::lastValue +Last value stored in strong::memoRoutine:: + +method::lastValues +Array of last values stored in strong::memoRoutine::, latest value is first in array. + +method::at +Returns ith item of array of last values stored in strong::memoRoutine:: (keep in mind reversed order: last value first) + +method::bufSize +Size of array of last values. + +method::srcPat +Instance variable getter and setter methods. + +method::length +Instance variable getter and setter methods. + +method::lengthStream +Instance variable getter and setter methods. + +method::memoRoutine +Instance variable getter and setter methods. + +method::count +Instance variable getter and setter methods. +Counts each call of next / value / resume / run on the strong::memoRoutine::. +If several Streams are derived from one PS each call of next on a derived Stream +will be counted by the strong::memoRoutine:: and thus by the PS. + +method::bufSeq +Returns items of the array strong::lastValues::, but in the order in which they appeared, i.e. +latest value is first in array. + +argument::dropNils +Boolean. If strong::dropNils:: is true (default), nils will be rejected from the array. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// PS used to store a sequence of 6 events + +( +p = Pbind( + \midinote, Pwhite(60, 90, 6), + \dur, Prand([0.2, 0.4], inf) +); + +// As the sequence ends with nil, nil is also stored in the buffer of PStream's MemoRoutine. +// Hence to store the whole sequence we must increase the buffer size by 1. + +q = PS(p, bufSize: 7); + +q.play; +) + + +// values are shifted, so latest are first + +q.lastValues + + +// method bufSeq gives items in order in which they appeared, dropping nils by default + +q.bufSeq + + +// repeat original sequence + +Pseq(q.bufSeq).play + + +// play in reverse order, as Stream has been finished there's also a nil to be dropped + +Pseq(q.lastValues.drop(1)).play + + +// counted embedding of value patterns +// PLx variants default to repeats = inf + +( +p = PLseq([ + PS(PLseq((60..65)), 3), + PS(PLseq((80..90)), Pwhite(2,5)) +]); + +x = Pbind( + \midinote, p, + \dur, 0.1 +).play; +) + +x.stop; + + +// counted embedding of event patterns + +( +p = Pbind( + \midinote, PLseq((55..70)) + Pfunc { [0, [4,5].choose] }, + \dur, 0.2 +); + +q = Pbind( + \midinote, PLseq((80..100)), + \dur, 0.05 +); + +x = PLseq([ + PS(p, Pwhite(2,6)), + PS(q, Pwhite(2,6)) +]).play; +) + +x.stop; + +:: + +note:: +Repeated streamifying of a PS is just like resuming a Stream (yes, PS behaves like ... a Stream). For getting a Stream to start at the beginning as defined by the Pattern enclosed by the PS, you'd have to generate a new PS, e.g. by reevaluating its definition or wrapping it into a Function. +:: + + +code:: + +p = PS(Pseries(), 5); + +// evaluate more than once + +p.asStream.all; + + + +// compare + +q = { PS(Pseries(), 5) }; + +// evaluate more than once + +q.value.asStream.all; + + + +// For recursively generating data see PSrecur. +// Referring to buffered last values of a PS can +// easily be done with method .at. + + +// canonical brown movement +// define 3 voices refering to a PS +// use separate PS to collect data +// plot + +( +p = PS(Pbrown(65, 90, 2.1), inf, 16); +p.iter.nextN(16); + +q = Pfunc { p[5] - 7 }; +r = Pfunc { p[10] - 14 }; +t = Pfunc { p[15] - 21 }; + +u = PS(Ptuple([p,q,r,t]), bufSize: 100); + +a = Plotter().superpose_(true).plotMode_(\plines); +a.value = u.iter.nextN(100).flop +) + +// playback stored pitches + +( +v = Pbind( + \midinote, Pseq(u.bufSeq), + \dur, 0.2 +).trace.play +) + +:: + diff --git a/HelpSource/Classes/PSPdiv.ext.schelp b/HelpSource/Classes/PSPdiv.ext.schelp new file mode 100644 index 0000000..fdd6485 --- /dev/null +++ b/HelpSource/Classes/PSPdiv.ext.schelp @@ -0,0 +1,4 @@ + +INSTANCEMETHODS:: + +private:: miSC_calcDivs diff --git a/HelpSource/Classes/PSPdiv.schelp b/HelpSource/Classes/PSPdiv.schelp new file mode 100755 index 0000000..fee2448 --- /dev/null +++ b/HelpSource/Classes/PSPdiv.schelp @@ -0,0 +1,524 @@ +CLASS:: PSPdiv +summary:: dynamic multi-layer pulse divider +categories:: Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Pspawner, Tutorials/Sieves_and_Psieve_patterns, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation + + +DESCRIPTION:: + + +PSPdiv controls the timing of one or several layers of event patterns by a single pulse pattern. In every layer single pulse durations or integer multiples ('division bases') of pulse durations can be divided by Integers or proportionally. For every layer the event pattern data can be given as event pattern or a function, which is generating an event pattern for every divisional operation. Division bases and divisions as well as the pulse itself can be controlled by patterns. + +PSPdiv is built on Pspawner and therefore allows sequential or parallel spawning: the type of embedding can be sequenced by a pattern for every divisional operation. So a single layer alone can produce a number of overlapping sequences. + +Time division in space notation scheme with two layers and embedding of sequential type: + +image::attachments/PSPdiv/PSPdiv_graph_1.png:: + +A sequence of regular or irregular strong::pulses:: is given as pattern of floats, these durations are marked as proportional spaces in the graphic. The sequence of strong::divBases:: collects groups of strong::pulses:: and divides them according to the sequence of strong::divs::. The resulting durations of each layer are again marked by proportional spacing, common entry points of layers are marked by emphasized vertical lines. + +Special thanks to Ron Kuivila for developing Pspawner, it's such a versatile class ! + + + +CLASSMETHODS:: + + +private::shiftDelta + + + +method::new + +Creates a new PSPdiv object. + + +argument::pulse +Duration or pattern of durations, given as beats. Defaults to 1. + +argument::evPat +An event pattern, a Function generating event patterns or: a SequenceableCollection thereof. If an event pattern is given, the durations of the current division, calculated from current values of strong::pulse::, strong::div:: and strong::divBase::, are inserted with the 'dur' key. If a Function is given, it will be passed 4 arguments: + +list:: +## an array of durations of the current division, based on the following arguments +## the current division number strong::div:: +## the current division base number strong::divBase:: +## the current division type strong::divType:: ('seq' or 'par') +:: + +The Function should return the event pattern to be scheduled for this division. The typical application would be using the array of durations in a Pseq with repeats = 1 as 'dur' value, though you are free to let it return any kind of event pattern. Layers are slightly shifted, so that the event from a pattern of lower index is calculated before an event from a pattern of higher index, if events are scheduled to happen at the same time. + +argument::div +Integer or array of array of numbers, determining a division of strong::divBase:: * strong::pulse:: beats or a pattern returning such or: a SequenceableCollection thereof. Defaults to 1. A single array of numbers is interpreted as indicator for several layers (see note below), hence the doubled array is necessary for a proportional division. + +argument::divBase +Integer determining the number of multiples of strong::pulse:: to be used as base of division or a pattern returning such or: a SequenceableCollection thereof. Defaults to 1. + + +argument::divType +Symbol 'seq' or 'par' or or a pattern returning such or: a SequenceableCollection thereof. Defaults to 'seq'. Determines the type of embedding according to Pspawner's convention. + +note:: +If one of the arguments strong::evPat::, strong::div::, strong::divBase:: and strong::divType:: is passed as SequenceableCollection of size > 1, a multitude of layers is assumed and the other args are interpreted accordingly. To avoid ambiguities only one size > 1 is allowed at maximum amongst these args (but more than one of them can be a SequenceableCollection of this size). Consequently a proportional strong::div:: arg for one layer must be passed in double brackets. +:: + + +INSTANCEMETHODS:: + +private::div, divBase, divType, evPat, pspDivInit, pulse + + + +section::Examples + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + + +anchor::Ex.1:: +subsection::Ex. 1: Basic functionality with one layer + +code:: + +// test SynthDef + +( +SynthDef(\varKlank, { |freq = 500, att = 0.01, rel = 0.1, sourceType = 0, + ringtime = 1, pan = 0, amp = 0.1| + var sig, source = Select.ar(sourceType, [ + BrownNoise.ar(0.05), + Impulse.ar(0) + ]); + sig = DynKlank.ar(`[freq * (1..8), amp * (8..1)/8, ringtime * (1!8)], source); + sig = Splay.ar(sig); + OffsetOut.ar(0, Balance2.ar(sig[0], sig[1], pan) * + EnvGen.ar(Env.perc(att, rel), doneAction: 2)) +}).add; +) + + +( +// base pattern +p = Pbind( + \instrument, \varKlank, + \midinote, Pwhite(65, 90), + \amp, 0.1, + \att, Pwhite(0.005, 0.02), + \rel, 2, + \sourceType, 1, + \ringtime, 2, + \pan, Pwhite(-0.3, 0.3) +); +) + + + +// div = 1, pulse not divided + +x = PSPdiv(0.8, p, 1).play; + +x.stop + + +// div as array of two items leads to expansion into two layers + +x = PSPdiv(0.8, p, [2, 1]).play; + +x.stop + + +// here div is interpreted as proportion for one layer + +x = PSPdiv(0.8, p, [[3, 1]] ).play; + +x.stop + + +// specifying per layer + +x = PSPdiv(0.8, [p, Pbindf(p, \rel, 0.1)], [1, [3, 2, 1]] ).play; + +x.stop + + + +// use with PL proxies + +( +// defaults, want to replace later on +~pulse = 0.8; +~div = 1; +~divBase = 1; +~divType = \seq; + +q = PSPdiv(PL(\pulse), p, PL(\div), PL(\divBase), PL(\divType)); +) + + + +// start playing + +x = q.play + + +// replace on the fly: +// alternating tuplets + +~div = PLseq([2, 3]); + + +// "dotted" notes, now we don't need double brackets as above as it's the source of the PL, +// not the PSPdiv arg + +~div = [3, 1]; + + +// acceleration and deceleration by pulse pattern control + +~pulse = Pseg(PLseq([0.8, 0.3]), 10) + + +( +// use divBase for base length control of tuplets +// here this could be written with div sequencing only also + +~pulse = 1; + +~div = PLseq([2, 6]); + +~divBase = PLseq([1, 1, 2]); +) + + +x.stop +:: + + + +anchor::Ex.2:: +subsection::Ex. 2: Parallel embedding with one layer + +SynthDef from link::#Ex.1:: + +code:: +( +// default values for proxies + +~pulse = 0.5; +~div = PLseq([6, 4]); +~divBase = 2; +~divType = \par; + + +// evPat argument now given as Function +// this especially makes sense in combination with parallel embedding +// otherwise parallel patterns would poll event data from a single event stream + + +p = { |durs| + // use durs calculated from pulse, div and divBase + var size = durs.size; + Pbind( + \dur, Pseq(durs), + \instrument, \varKlank, + \midinote, Pseq(~baseStream.next + rrand(0, 7) + (0..size)), + \amp, 0.1, + \att, Pwhite(0.005, 0.02), + \rel, ~releaseStream.next, + \ringtime, 2, + \sourceType, 1, + \pan, ~panStream.next + ) +}; + +// these streams deliver items for each embedding + +~baseStream = PLseq([60, 70, 80]).iter; +~releaseStream = Pn(Pshuf([2, 0.6, 0.2])).iter; +~panStream = Pwhite(-0.8, 0.8).iter; + + +// we still have only one layer, but it will overlap + +q = PSPdiv(PL(\pulse), p, PL(\div), PL(\divBase), PL(\divType)); +) + + +// start + +x = q.play + + +// change to sequential embedding + +~divType = \seq; + + +// type of embedding can be sequenced too + +~divType = PLrand([\seq, \par, \par]); + + +// default divBase was 2, allow shorter division bases + +~divBase = PLrand([1, 2]); + + +x.stop +:: + + + + +anchor::Ex.3:: +subsection::Ex. 3: Ornamenting a line with a second layer + +SynthDef from link::#Ex.1:: + +code:: +( +p = Pbind( + \instrument, \varKlank, + // basic melodic line, data stored in variable for use by ornamentation + \midinote, (Pn(Pshuf([72, 74, 76, 79, 81])).collect { |x| ~m = x; }) + + // random broadening of line + PLrand([[-14, 0], [0, 14]]), + \amp, 0.15, + \att, Pwhite(0.01, 0.02), + \rel, 3, + \sourceType, 1, + \ringtime, 3, + \pan, Pwhite(-0.3, 0.3) +); + +~releaseStream = Pn(Pshuf([2, 0.5, 0.2])).iter; +~panStream = Pwhite(-0.8, 0.8).iter; +~dirStream = PLseq([1, -1]).iter; + +// defines trill pattern for every event from melodic line + +q = { |durs| + // use durs calculated from pulse, div and divBase + var size = durs.size, midibase = ~m; + Pbind( + \dur, Pseq(durs), + \instrument, \varKlank, + // define trill alternating above and below basic melodic line + \midinote, Pn(rrand(4, 9) * ~dirStream.next, size) + PLseq([0, 1]) + midibase, + \amp, 0.1, + \att, Pwhite(0.005, 0.02), + \rel, ~releaseStream.next, + \ringtime, 2, + \sourceType, 1, + \pan, ~panStream.next + ) +}; + +// default values for PL proxies, want to replace later on + +~pulse = PLshufn([1, 1, 2]/2); +~div = PLrand([4, 6, 8]); +~divBase = 1; +~divType = \seq; + +r = PSPdiv( + PL(\pulse), + [p, q], + [1, PL(\div)], + [1, PL(\divBase)], + [1, PL(\divType)] +); +) + + +// start with sequential embedding: trill on every note, variuos divisions + +x = r.play + + +// change to parallel embedding of trills, overlapping + +( +~divBase = 2; +~div = PLrand([8, 12, 16]); +~divType = \par; +) + +x.stop +:: + + + + + + +anchor::Ex.4:: +subsection::Ex. 4: Polyrhythmics of several layers + +SynthDef from link::#Ex.1:: + +code:: +// three layers using varying pentatonic scales shifted by sixth tones + +( +// staccato layer +p = Pbind( + \instrument, \varKlank, + \midinote, PLshufn([0, 2, 4, 7, 9]) + Pn(Pstutter(15, Pwhite(80, 100, 1))) + + 0.6 + [0, -14], + // use some rests + \amp, 0.06, + \att, Pwhite(0.01, 0.02), + \rel, 0.15, + \sourceType, 1, + \ringtime, 3, + \pan, Pwhite(-0.3, 0.3) +); + +// long release layer +q = Pbind( + \instrument, \varKlank, + \midinote, PLshufn([0, 2, 4, 7, 9]) + Pn(Pstutter(20, Pwhite(60, 80, 1))) + + PLrand([[-14, 0]]) + PLrand([0, 12]), + \amp, 0.08, + \att, Pwhite(0.01, 0.02), + \rel, 2, + \sourceType, 1, + \ringtime, 2, + \pan, Pwhite(-0.3, 0.3) +); + +// "drum" layer +r = Pbind( + \instrument, \varKlank, + \midinote, PLshufn([0, 2, 4, 7, 9]) + Pn(Pstutter(25, Pwhite(35, 50, 1))) + + 0.3 + [-12, 0], + \amp, 0.02, + \att, Pwhite(0.01, 0.02), + \rel, 0.35, + \sourceType, 0, + \ringtime, 1, + \pan, Pwhite(-0.3, 0.3) +); + +// default values for PL proxies, want to replace later on + +~pulse = PLshufn([1, 1, 2] * 5/9); + +~div0 = PLshufn([4, 8]); +~div1 = PLshufn([2, 3, 4]); +~div2 = PLshufn([2, 4]); +~divBase = 1; +~divType = \seq; + +u = PSPdiv( + PL(\pulse), + [p, q, r], + [PL(\div0), PL(\div1), PL(\div2)], + // will be exapanded to array of 3 PLs with same symbol reference + PL(\divBase), + PL(\divType) +); +) + + +// start + +x = u.play + + +// vary pulse + +~pulse = PLshufn([1, 1.5, 2.5, 3] * 5/9); + +~pulse = 1; + +~div0 = PLshufn([4, 6, 8]); + +~div2 = PLshufn([2, 4, 6]); + +~pulse = PLshufn([1, 1, 9/8]); + +x.stop; + +:: + + + + +anchor::Ex.5:: +subsection::Ex. 5: Granulation, control of many layers + +SynthDef from link::#Ex.1:: + +code:: + +( +~amp = 0.05; +~att = 0.005; +~rel = 0.05; +~sourceType = 0; +~ringtime = 1; + +~pan = PLseq([0.8, -0.8]); + +// Pbind generator, patterns will stick to midinotes +p = { |midinote| Pbind( + \instrument, \varKlank, + \midinote, midinote, + \amp, PL(\amp), + \att, PL(\att), + \rel, PL(\rel), + \sourceType, PL(\sourceType), + \ringtime, PL(\ringtime), + \pan, PL(\pan) +) }; + +// produce an array of Pbinds, covering a whole tone cluster +q = ((1, 3..51) + 40).collect(p.(_)); + +~size = q.size; + +// same pattern source for each PL, +// but for each midinote divisions per pulse can vary + +~div = Pfunc { (2 ** (1..4)).choose.asInteger }; +~divBase = 1; + +~pulse = 1; +~rel = 0.015; +~sourceType = 1; + +// as q is an array the args 'div' and 'divBase' will be expanded to arrays +u = PSPdiv(PL(\pulse), q, PL(\div), PL(\divBase)); +) + + + +x = u.play + +// this setting exchanges the source of all PL patterns expanded as 'div' arg + +~div = Pfunc { (2 ** (1..6)).choose.asInteger } + + +// also with divBase, layers are decorrelated as each stream from this pattern acts differently + + +~divBase = PLrand([1, 2]) + +~divBase = PLrand([1, 2, 3]) + + +~pulse = 1/4 + +x.stop +:: + + diff --git a/HelpSource/Classes/PSVdif.schelp b/HelpSource/Classes/PSVdif.schelp new file mode 100644 index 0000000..7881e56 --- /dev/null +++ b/HelpSource/Classes/PSVdif.schelp @@ -0,0 +1,52 @@ + +CLASS::PSVdif +summary::Sieve pattern for difference of integer generators with point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for difference of integer generators with point output. Corresponds to Sieve's methods link::Classes/Sieve#*dif:: and link::Classes/Sieve#-dif::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVdif object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVdif([3, 2], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 30) + +q = PSVdif([1, a], 20) + +q.asStream.all + + +r = PSVdif([1, a], limit: 15) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVdif_i.schelp b/HelpSource/Classes/PSVdif_i.schelp new file mode 100644 index 0000000..1362ba3 --- /dev/null +++ b/HelpSource/Classes/PSVdif_i.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVdif_i +summary::Sieve pattern for difference of integer generators with interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for difference of integer generators with interval output. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVdif_i object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned until default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVdif_i([3, 2], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 30) + +q = PSVdif_i([1, a], 20) + +q.asStream.all + + +r = PSVdif_i([1, a], limit: 15) + +r.asStream.all + +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVdif_o.schelp b/HelpSource/Classes/PSVdif_o.schelp new file mode 100644 index 0000000..88687cc --- /dev/null +++ b/HelpSource/Classes/PSVdif_o.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVdif_o +summary::Sieve pattern for difference of integer generators with offsets and point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for difference of integer generators with offsets and point output. Corresponds to Sieve's methods link::Classes/Sieve#*dif_o:: and link::Classes/Sieve#-dif_o::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVdif_o object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVdif_o([3, 1, 5, -2], 10) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVdif_o([a, 90, 3, 80], 20) + +q.asStream.all + + +r = PSVdif_o([a, 90, 3, 80], limit: 100) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVdif_oi.schelp b/HelpSource/Classes/PSVdif_oi.schelp new file mode 100644 index 0000000..8c345ab --- /dev/null +++ b/HelpSource/Classes/PSVdif_oi.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVdif_oi +summary::Sieve pattern for difference of integer generators with offsets and interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for difference of integer generators with offsets and interval output. Corresponds to Sieve's methods link::Classes/Sieve#*dif_oi:: and link::Classes/Sieve#-dif_oi::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVdif_oi object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned up to default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVdif_oi([5, 0, 10, -20], 20) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVdif_oi([1, 0, a, -2], 20) + +q.asStream.all + + +r = PSVdif_oi([1, 0, 10, -2], limit: 20) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVop.schelp b/HelpSource/Classes/PSVop.schelp new file mode 100644 index 0000000..41a7103 --- /dev/null +++ b/HelpSource/Classes/PSVop.schelp @@ -0,0 +1,73 @@ + +CLASS::PSVop +summary::Sieve pattern for arbitrary set operations of integer generators with point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for arbitrary set operations of integer generators with point output. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVop object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::op +One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union', +'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'. + +argument::difIndex +Integer or a Pattern/Stream to produce such. +Determines the generator from which will be subtracted in case of operation 'dif'. +Defaults to 0. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +// equivalent + +x = PSVop([3, 5], \sd) +y = PSVsymdif([3, 5]) + +x.asStream.nextN(15) +y.asStream.nextN(15) + + +// sequencing of logical operations + +p = PSVop([3, 3], Pseq([\u, \sd], inf)) + +p.asStream.nextN(15) + + +// specify difference + +q = PSVop([2, 5], \d, 1) + +q.asStream.nextN(100) + + +r = PSVop([2, 5], \d, 0) + +r.asStream.nextN(100) +:: + diff --git a/HelpSource/Classes/PSVop_i.schelp b/HelpSource/Classes/PSVop_i.schelp new file mode 100644 index 0000000..acc5ad6 --- /dev/null +++ b/HelpSource/Classes/PSVop_i.schelp @@ -0,0 +1,72 @@ + +CLASS::PSVop_i +summary::Sieve pattern for arbitrary set operations of integer generators with interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for arbitrary set operations of integer generators with interval output. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVop_i object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::op +One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union', +'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'. + +argument::difIndex +Integer or a Pattern/Stream to produce such. +Determines the generator from which will be subtracted in case of operation 'dif'. +Defaults to 0. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned until default summation limit of 65536. + + +SECTION::Examples + +code:: +// equivalent + +x = PSVop_i([3, 5], \sd) +y = PSVsymdif_i([3, 5]) + +x.asStream.nextN(15) +y.asStream.nextN(15) + + +// sequencing of logical operations + +p = PSVop_i([3, 3], Pseq([\u, \sd], inf)) + +p.asStream.nextN(15) + + +// specify difference + +q = PSVop_i([2, 5], \d, 1) + +q.asStream.nextN(100) + + +r = PSVop_i([2, 5], \d, 0) + +r.asStream.nextN(100) +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVop_o.schelp b/HelpSource/Classes/PSVop_o.schelp new file mode 100644 index 0000000..37cb8b8 --- /dev/null +++ b/HelpSource/Classes/PSVop_o.schelp @@ -0,0 +1,75 @@ + +CLASS::PSVop_o +summary::Sieve pattern for arbitrary set operations of integer generators with offsets and point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for arbitrary set operations of integer generators with offsets and point output. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVop_o object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Offsets must be integers. + +argument::op +One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union', +'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'. + +argument::difIndex +Integer or a Pattern/Stream to produce such. +Determines the generator from which will be subtracted in case of operation 'dif'. +Defaults to 0. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +// equivalent + +x = PSVop_o([3, 1, 5, 0], \sd) +y = PSVsymdif_o([3, 1, 5, 0]) + +x.asStream.nextN(15) +y.asStream.nextN(15) + + +// sequencing of logical operations + +p = PSVop_o([3, 1, 2, 0], Pseq([\s, \u, \u], inf)) + +p.asStream.nextN(15) + + +// specify difference + +q = PSVop_o([3, 1, 5, 0], \d, 1) + +q.asStream.nextN(10) + + +r = PSVop_o([3, 1, 5, 0], \d, 0) + +r.asStream.nextN(10) +:: + + diff --git a/HelpSource/Classes/PSVop_oi.schelp b/HelpSource/Classes/PSVop_oi.schelp new file mode 100644 index 0000000..1b29134 --- /dev/null +++ b/HelpSource/Classes/PSVop_oi.schelp @@ -0,0 +1,74 @@ + +CLASS::PSVop_oi +summary::Sieve pattern for arbitrary set operations of integer generators with offsets and interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o + +DESCRIPTION:: +Pattern for arbitrary set operations of integer generators with offsets and interval output. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVop_oi object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +Offsets must be integers. + +argument::op +One of the Symbols 'u', 's', 'sd', 'd' as abbreviations for set operations 'union', +'sect', 'symdif', 'dif' or a Pattern/Stream to produce such. Defaults to 'u'. + +argument::difIndex +Integer or a Pattern/Stream to produce such. +Determines the generator from which will be subtracted in case of operation 'dif'. +Defaults to 0. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned up to default summation limit of 65536. + + +SECTION::Examples + +code:: +// equivalent + +x = PSVop_oi([3, 1, 5, 0], \sd) +y = PSVsymdif_oi([3, 1, 5, 0]) + +x.asStream.nextN(15) +y.asStream.nextN(15) + + +// sequencing of logical operations + +p = PSVop_oi([3, 1, 2, 0], Pseq([\s, \u, \u], inf)) + +p.asStream.nextN(15) + + +// specify difference + +q = PSVop_oi([3, 1, 5, 0], \d, 1) + +q.asStream.nextN(10) + + +r = PSVop_oi([3, 1, 5, 0], \d, 0) + +r.asStream.nextN(10) +:: + diff --git a/HelpSource/Classes/PSVsect.schelp b/HelpSource/Classes/PSVsect.schelp new file mode 100644 index 0000000..3e52194 --- /dev/null +++ b/HelpSource/Classes/PSVsect.schelp @@ -0,0 +1,52 @@ + +CLASS::PSVsect +summary::Sieve pattern for intersection of integer generators with point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for intersection of integer generators with point output. Corresponds to Sieve's methods link::Classes/Sieve#*sect:: and link::Classes/Sieve#-sect::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsect object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVsect([3, 5], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 1000) + +q = PSVsect([a, 100], 10) + +q.asStream.all + + +r = PSVsect([a, 100], limit: 500) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsect_i.schelp b/HelpSource/Classes/PSVsect_i.schelp new file mode 100644 index 0000000..fe220f1 --- /dev/null +++ b/HelpSource/Classes/PSVsect_i.schelp @@ -0,0 +1,52 @@ + +CLASS::PSVsect_i +summary::Sieve pattern for intersection of integer generators with interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for intersection of integer generators with interval output. Corresponds to Sieve's methods link::Classes/Sieve#*sect_i:: and link::Classes/Sieve#-sect_i::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsect_i object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned until default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVsect_i([3, 5], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 1000) + +q = PSVsect_i([a, 100], 10) + +q.asStream.all + + +r = PSVsect_i([a, 100], limit: 500) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsect_o.schelp b/HelpSource/Classes/PSVsect_o.schelp new file mode 100644 index 0000000..f2b4e4d --- /dev/null +++ b/HelpSource/Classes/PSVsect_o.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVsect_o +summary::Sieve pattern for intersection of integer generators with offsets and point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for intersection of integer generators with offsets and point output. Corresponds to Sieve's methods link::Classes/Sieve#*sect_o:: and link::Classes/Sieve#-sect_o::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsect_o object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVsect_o([3, 1, 5, -2], 10) + +p.asStream.nextN(15) + + +a = Sieve(4, 200) + +q = PSVsect_o([a, 90, 10, 100], 20) + +q.asStream.all + + +r = PSVunion_o([a, 50, 10, -100], limit: 100) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsect_oi.schelp b/HelpSource/Classes/PSVsect_oi.schelp new file mode 100644 index 0000000..3baa8e3 --- /dev/null +++ b/HelpSource/Classes/PSVsect_oi.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVsect_oi +summary::Sieve pattern for intersection of integer generators with offsets and interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for intersection of integer generators with offsets and interval output. Corresponds to Sieve's methods link::Classes/Sieve#*sect_oi:: and link::Classes/Sieve#-sect_oi::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsect_oi object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned up to default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVsect_oi([10, 31, 50, 1], 20) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVsect_oi([a, 20, 10, 0], 5) + +q.asStream.all + + +r = PSVsect_oi([a, 20, 10, 0], limit: 25) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsymdif.schelp b/HelpSource/Classes/PSVsymdif.schelp new file mode 100644 index 0000000..de1bff9 --- /dev/null +++ b/HelpSource/Classes/PSVsymdif.schelp @@ -0,0 +1,52 @@ + +CLASS::PSVsymdif +summary::Sieve pattern for symmetric difference of integer generators with point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for symmetric difference of integer generators with point output. Corresponds to Sieve's methods link::Classes/Sieve#*symdif:: and link::Classes/Sieve#-symdif::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsymdif object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVsymdif([3, 5], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 50) + +q = PSVsymdif([a, 2], 15) + +q.asStream.all + + +r = PSVsymdif([a, 2], limit: 20) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsymdif_i.schelp b/HelpSource/Classes/PSVsymdif_i.schelp new file mode 100644 index 0000000..256d299 --- /dev/null +++ b/HelpSource/Classes/PSVsymdif_i.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVsymdif_i +summary::Sieve pattern for symmetric difference of integer generators with interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for symmetric difference of integer generators with interval output. Corresponds to Sieve's methods link::Classes/Sieve#*symdif_i:: and link::Classes/Sieve#-symdif_i::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsymdif_i object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned until default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVsymdif_i([3, 5], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 30) + +q = PSVsymdif_i([a, 100], 10) + +q.asStream.all + + +r = PSVsymdif_i([a, 100], limit: 1000) + +r.asStream.all + +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsymdif_o.schelp b/HelpSource/Classes/PSVsymdif_o.schelp new file mode 100644 index 0000000..3e05054 --- /dev/null +++ b/HelpSource/Classes/PSVsymdif_o.schelp @@ -0,0 +1,54 @@ + +CLASS::PSVsymdif_o +summary::Sieve pattern for symmetric difference of integer generators with offsets and point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for symmetric difference of integer generators with offsets and point output. Corresponds to Sieve's methods link::Classes/Sieve#*symdif_o:: and link::Classes/Sieve#-symdif_o::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsymdif_o object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVunion_o([3, 1, 5, -2], 10) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVunion_o([a, 90, 10, 100], 20) + +q.asStream.all + + +r = PSVsymdif_o([a, 90, 10, 80], limit: 100) + +r.asStream.all + +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVsymdif_oi.schelp b/HelpSource/Classes/PSVsymdif_oi.schelp new file mode 100644 index 0000000..8d1ba99 --- /dev/null +++ b/HelpSource/Classes/PSVsymdif_oi.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVsymdif_oi +summary::Sieve pattern for symmetric difference of integer generators with offsets and interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for symmetric difference of integer generators with offsets and interval output. Corresponds to Sieve's methods link::Classes/Sieve#*symdif_oi:: and link::Classes/Sieve#-symdif_oi::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVsymdif_oi object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned up to default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVsymdif_oi([10, 0, 50, 1], 20) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVsymdif_oi([a, 0, 10, 100], 20) + +q.asStream.all + + +r = PSVsymdif_oi([a, 0, 10, 100], limit: 120) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVunion.schelp b/HelpSource/Classes/PSVunion.schelp new file mode 100644 index 0000000..3434319 --- /dev/null +++ b/HelpSource/Classes/PSVunion.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVunion +summary::Sieve pattern for union of integer generators with point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for union of integer generators with point output. Corresponds to Sieve's methods link::Classes/Sieve#*union:: and link::Classes/Sieve#-union::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVunion object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVunion([3, 5], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 30) + +q = PSVunion([a, 100], 10) + +q.asStream.all + + +r = PSVunion([a, 100], limit: 1000) + +r.asStream.all + +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVunion_i.schelp b/HelpSource/Classes/PSVunion_i.schelp new file mode 100644 index 0000000..ffc1050 --- /dev/null +++ b/HelpSource/Classes/PSVunion_i.schelp @@ -0,0 +1,52 @@ + +CLASS::PSVunion_i +summary::Sieve pattern for union of integer generators with interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for union of integer generators with interval output. Corresponds to Sieve's methods link::Classes/Sieve#*union_i:: and link::Classes/Sieve#-union_i::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVunion_i object. + +argument::genList +An array of generators. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned until default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVunion_i([3, 5], 10) + +p.asStream.nextN(15) + + +a = Sieve(7, 30) + +q = PSVunion_i([a, 100], 10) + +q.asStream.all + + +r = PSVunion_i([a, 100], limit: 1000) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVunion_o.schelp b/HelpSource/Classes/PSVunion_o.schelp new file mode 100644 index 0000000..6897cb2 --- /dev/null +++ b/HelpSource/Classes/PSVunion_o.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVunion_o +summary::Sieve pattern for union of integer generators with offsets and point output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for union of integer generators with offsets and point output. Corresponds to Sieve's methods link::Classes/Sieve#*union_o:: and link::Classes/Sieve#-union_o::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVunion_o object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which integers can be returned by the stream. +If no limit is passed, returned integers might go up to default limit 65536. + + +SECTION::Examples + +code:: +p = PSVunion_o([3, 1, 5, -2], 10) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVunion_o([a, 90, 10, 100], 20) + +q.asStream.all + + +r = PSVunion_o([a, 10, 3, 7], limit: 20) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSVunion_oi.schelp b/HelpSource/Classes/PSVunion_oi.schelp new file mode 100644 index 0000000..040abe6 --- /dev/null +++ b/HelpSource/Classes/PSVunion_oi.schelp @@ -0,0 +1,53 @@ + +CLASS::PSVunion_oi +summary::Sieve pattern for union of integer generators with offsets and interval output +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Pattern for union of integer generators with offsets and interval output. Corresponds to Sieve's methods link::Classes/Sieve#*union_oi:: and link::Classes/Sieve#-union_oi::. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +method::new + +Creates a new PSVunion_oi object. + +argument::genList +An array of generators and corresponding offsets. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +Offsets must be integers. + +argument::maxLength +Integer. Maximum number of items, which the stream will return. +Defaults to inf. + +argument::limit +Integer. Limit up to which intervals can be returned by the stream. +If no limit is passed, integer intervals might be returned up to default summation limit of 65536. + + +SECTION::Examples + +code:: +p = PSVunion_oi([10, 0, 50, 1], 20) + +p.asStream.nextN(15) + + +a = Sieve(4, 20) + +q = PSVunion_oi([a, 0, 10, 100], 20) + +q.asStream.all + + +r = PSVunion_oi([a, 0, 10, 100], limit: 120) + +r.asStream.all +:: \ No newline at end of file diff --git a/HelpSource/Classes/PSdup.schelp b/HelpSource/Classes/PSdup.schelp new file mode 100644 index 0000000..391aba8 --- /dev/null +++ b/HelpSource/Classes/PSdup.schelp @@ -0,0 +1,172 @@ +CLASS:: PSdup +summary:: Pattern which returns last values from other patterns via PSx +categories::Libraries>miSCellaneous>PSx stream patterns, Streams-Patterns-Events>PSx stream patterns +related:: Overviews/miSCellaneous, Tutorials/PSx_stream_patterns, Classes/MemoRoutine, Classes/PS, Classes/PSrecur, Classes/PSloop + + +DESCRIPTION:: + + +PSdup uses the storage functionality of other PSx patterns. To track a value stream or event stream from a pattern you'd have to wrap the pattern into a PSx. + + + +CLASSMETHODS:: + +method::new + +Creates a new PSdup object. + +argument::psxPat +Source pattern, must be a PSx pattern. + +argument::length +Number of output items, may be pattern or stream, defaults to inf. + +argument::bufSize +Size of buffer to store last values, defaults to 1. + +argument::copyItems +Determines if and how to copy the last items from strong::psxPat::'s buffer +which are either non-Sets or member of Sets. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). +Other values are interpreted as 0. Defaults to 0. + +0: original item + +1: copy item + +2: deepCopy item + +argument::copySets +Determines if and how to copy the last items from strong::psxPat::'s buffer +which are Sets. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). +Other values are interpreted as 0. Defaults to 1. + +0: original Set + +1: copy Set + +note:: +The distinction of copying items and sets makes sense in the case of event streams. Per default Events are copied (strong::copySets:: == 1), not their values (strong::copyItems:: == 0). By playing Events those are used to store additional data (synth ids, msgFuncs …) which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use MemoRoutine - copied Events will not contain this additional data. If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured then copying makes no sense, this is the normal case, so copyItems defaults to 0. When going to alter the ouput, you might want to set strong::copyItems:: to 1 for a PSx returning simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set strong::copySets:: to 1 and strong::copyItems:: to 2 (an option strong::copySets:: == 2 doesn't exist as it would be contradictory in combination with strong::copyItems:: < 2). +:: + + +note:: +Copy options concern copying into PSdup's buffer as well as the output of a Stream derived from the PSdup. When such a Stream is outputting copies this prevents unintended altering of items stored in the buffer of strong::psxPat::. On the other hand storing copies in PSdup's buffer prevents these from being altered unintendedly. +:: + + +INSTANCEMETHODS:: + +method::psxPat +Instance variable getter and setter methods. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// copying of value patterns +// PSdup needs a PSx as input, as its value storage is used, +// so it's easiest to wrap the original pattern into a PS + +( +p = PS(Pseries()); +q = PSdup(p); + +// PSx patterns have a state and, in this regard, behave like Streams. +// However, like other Patterns, for generating they must be made to Streams +// which are the objects actually returning items. + +x = p.asStream; +y = q.asStream; +) + +// y follows x (as in the array left is evaluated before right) + +( +a = []; +10.do { a = a.add([x.next, y.next]) }; +a; +) + + +// get values from original Pattern / Stream + +x.nextN(10) + +// now y copies the last value of x resp. p + +y.nextN(10) + + + +// data sharing with event patterns + +( +p = Pbind( + \midinote, Pwhite(60, 90) + PLrand([0, 0, [0, -3]]), + \dur, PLrand([0.2, 0.4]), + \amp, PLrand([0.07, 0.12, 0.2]), + \type, Pfunc { 0.1.coin.if { \rest }{ \note } }, + \pan, 1 +); + +q = PS(p); + +// use PSdup as base for alterings +// it takes the last event stored in PS(p) + +r = Pbindf(Padd(\midinote, PLrand([1,2,4,5]), PSdup(q)), \pan, -1); + +// as in general with event stream data sharing it's recommended to invent a small delta +// between streams, here this is extended to a clear echo + +t = Ptpar([0, q, 0.1, r]).trace.play; +) + +t.stop; + + +// data sharing with event patterns, more voices + + +( +p = Pbind( + \midinote, Pwhite(50.0, 65), + \dur, PLrand([0.7, 0.9, 1.2]), + \amp, PLrand([0.1, 0.15, 0.2]), + \legato, 0.1 +); + +q = PS(p); + +// make pattern maker Function for parametrized alterings + +f = { |div, add| Padd(\midinote, add, Pmul(\dur, 1 / div, PSdup(q))) }; +d = 0.001; + +t = Ptpar([ + 0, q, + d, f.(2, 5 + PLrand([0, [0, 12.05]])), + d*2, f.(4, 7 + PLrand([0, [0, 12.1]])), + d*3, f.(8, 10 + PLrand([0, [0, 12.2]])) +]).play +) + + +t.stop; + + +:: + + \ No newline at end of file diff --git a/HelpSource/Classes/PSloop.schelp b/HelpSource/Classes/PSloop.schelp new file mode 100644 index 0000000..5ef711c --- /dev/null +++ b/HelpSource/Classes/PSloop.schelp @@ -0,0 +1,681 @@ +CLASS:: PSloop +summary:: Pattern to derive loops from a given Pattern +categories::Libraries>miSCellaneous>PSx stream patterns, Streams-Patterns-Events>PSx stream patterns +related:: Overviews/miSCellaneous, Tutorials/PSx_stream_patterns, Classes/MemoRoutine, Classes/PS, Classes/PSdup, Classes/PSrecur + +DESCRIPTION:: + +Although PSloop is not a subclass of PStream, instances of PSloop have a state by storing a PStream of the source pattern in an instance variable. So the specific characteristics of PSx patterns are indirectly inherited by PSloop. This especially concerns the way to generate new, fresh PSloop streams, see examples in link::Tutorials/PSx_stream_patterns::. + +Note that impossible lookBack and indices values will be clipped, see descriptions of args strong::bufSize::, strong::lookBack:: and strong::indices::. + + + +CLASSMETHODS:: + +method::new + +Creates a new PSloop object. + +argument::srcPat +Source pattern for looping, can be value or event pattern. + +argument::length +Number of output items, may be Pattern or Stream, defaults to inf. + +argument::bufSize +Integer size of buffer to store last values. Determines and clips the maximum strong::lookBack:: index. Defaults to 1. + + +argument::lookBack +Non-negative Integer determining the depth of looking backwards when looping, may be Pattern or Function also. +Default 0 means going on with the Stream of the source pattern strong::srcPat::. +If no strong::indices:: is given, a positive Integer strong::lookBack:: = n causes straight looping from the nth item +in the past up to the last item of the Stream. +If strong::indices:: is given, an index array is produced by this function applied to strong::lookBack:: = n. +The array refers to the nth item in the past by array index 0. +If strong::lookBack:: values are derived from a Pattern or Function, they might be polled at the end of the loops +or with every item, this is determined by the current value of strong::doSkip::. +strong::lookBack:: will be clipped by strong::bufSize:: if it is greater than the latter. + + +argument::doSkip +Integer or Boolean or: Function or Stream returning such. +Determines if strong::lookBack:: values are polled at the end of loops (0, false) or within loops (1, true) also. +In the latter case a new strong::lookBack:: value will stop the current loop and start a new one. Defaults to 1. + +argument::loopFunc +Function or Pattern returning Functions, to be applied to items of the loops. +If Functions are streamed by passing a Function-generating Pattern strong::loopFuncPerItem:: determines if +a Function will be applied per item (1, true) or to all items of a loop (0, false). +When loopFunc is nil or the strong::loopFunc:: stream returns nil, no Function is applied. + +argument::loopFuncPerItem +Integer or Boolean or: Function or Stream returning such. +If strong::loopFunc:: is given, strong::loopFuncPerItem:: determines if a Function will be applied per item (1, true) or +to all items of a loop (0, false). + +argument::loopFuncAsGoFunc +Integer or Boolean or: Function or Stream returning such. +Determines if strong::loopFunc:: will be used for new items outside loops too (1, true). +In this case strong::goFunc:: is ignored (resp. nothing is polled from a goFunc stream) and nil values +from the loopFunc stream are also taken over (no Function is applied outside loops then). + +argument::goFunc +Function or Pattern returning Functions, to be applied to new items outside loops. +When strong::goFunc:: is nil or the strong::goFunc:: stream returns nil, no Function is applied. +Note that goFunc has no effect when strong::loopFuncAsGoFunc:: determines to use strong::loopFunc:: generally. + +argument::indices +SequenceableCollection, Function, or Pattern returning SequenceableCollections or Functions. +If no strong::indices:: is passed (default nil) a positive Integer strong::lookBack:: = n causes straight looping from the nth item +in the past up to the last item of the Stream. +A SequenceableCollection passed via strong::indices:: is taken as array of indices and determines the items of the buffer, +identifying the nth item in the past with array index 0. +A Function passed via strong::indices:: takes strong::lookBack:: = n as argument and must return an index array which also +determines the items of the buffer, identifying the nth item in the past with array index 0. +A Pattern passed via strong::indices:: should be defined to generate Functions or SequenceableCollections, +which are interpreted in the same way as above. +In case of a Pattern a new strong::indices:: value is polled within a loop if current strong::doSkip:: equals 1 or true. +strong::indices:: will be clipped by strong::lookBack:: - 1, strong::lookBack:: itself might be clipped by strong::bufSize::. + + +argument::copyItems +Argument passed to the PS wrapper of strong::srcPat::. See link::Classes/PS::. +Determines if and how to copy items which are either non-Sets or member of Sets. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). +Other values are interpreted as 0. Defaults to 0. + +0: original item + +1: copy item + +2: deepCopy item + +argument::copySets +Argument passed to the PS wrapper of strong::srcPat::. See link::Classes/PS::. +Determines if and how to copy Sets (and hence Events). +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). +Other values are interpreted as 0. Defaults to 1. + +0: original Set + +1: copy Set + +note:: +The distinction of copying items and sets makes sense in the case of event streams. Per default Events are copied (strong::copySets:: == 1), not their values (strong::copyItems:: == 0). By playing Events those are used to store additional data (synth ids, msgFuncs …) which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use MemoRoutine - copied Events will not contain this additional data. If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured then copying makes no sense, this is the normal case, so copyItems defaults to 0. When going to alter the ouput, you might want to set strong::copyItems:: to 1 for a PSx returning simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set strong::copySets:: to 1 and strong::copyItems:: to 2 (an option strong::copySets:: == 2 doesn't exist as it would be contradictory in combination with strong::copyItems:: < 2). +:: + + +note:: +Copy options concern copying into PSrecur's buffer as well as the output of a Stream derived from the PSrecur. When such a Stream is outputting copies this prevents unintended altering of items stored in the buffer of PSrecur. On the other hand storing copies in PSrecur's buffer prevents these from being altered unintendedly. +:: + + +INSTANCEMETHODS:: + +method::psPat +Instance variable getter and setter methods. +strong::psPat:: holds a Pstream with args strong::srcPat::, strong::length::, strong::bufSize::, strong::copyItems::, strong::copySets::. + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +anchor::Ex.1a:: +subsection::Ex.1a: PSloop used as value pattern + +code:: +// straight usage as value pattern for midinotes + +( +// lookBack determines number of items to loop, must start with 0 (no loop), +// doSkip determines if loops should be completed or not with new lookBack values. + +// Passing both via Functions enables to set on the fly, +// enable immediate loop change by setting doSkip to 1 + +~lookBack = 0; +~doSkip = true; + +p = Pbind( + \dur, 1/5, + \midinote, PSloop( + Prand((60..80), inf), + bufSize: 10, + lookBack: { ~lookBack }, + doSkip: { ~doSkip } + ) +).play +) + +// wait a bit to fill buffer +// keep running, set loop lengths immediately + +~lookBack = 4 + +~lookBack = 2 + +~lookBack = 7 + + +// change to skip per loop (default) + +~doSkip = false + +~lookBack = 3 + +~lookBack = 5 + +~lookBack = 9 + + +// go on + +~lookBack = 0 + +p.stop; + +:: + + +anchor::Ex.1b:: +subsection::Ex.1b: PSloop used as event pattern + +code:: +// rhythms are looped too + +( +~lookBack = 0; +~doSkip= 1; + +p = PSloop( + Pbind( + \dur, Pn(Pshuf([1, 1, 2, Pseq(2!3/3)]/5)), + \midinote, Prand((60..80), inf) + ), + bufSize: 10, + lookBack: { ~lookBack }, + doSkip: { ~doSkip} +).play +) + +// wait a bit to fill buffer +// keep running, set loop lengths immediately + +~lookBack = 6 + +~lookBack = 5 + + +// go on and loop again + +~lookBack = 0 + +~lookBack = 7 + + +p.stop; +:: + + + +anchor::Ex.2a:: +subsection::Ex.2a: PSloop used as value pattern, lookBack given as pattern + +code:: +// lookBack passed as pattern, +// lookBack pattern must start with zeros, +// otherwise it will immediately stop with buffer values = nil + +// PSloop as value pattern: in general rhythms aren't looped + +( +p = Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, PSloop( + Prand((60..80), inf), + bufSize: 10, + lookBack: Pseq([0, 0, 0, 2, 2, 3, 3], inf) + ) +).play +) + +p.stop +:: + + + + +anchor::Ex.2b:: +subsection::Ex.2b: PSloop used as event pattern, lookBack given as pattern + +code:: +// rhythms looped too + +( +p = PSloop( + Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, Prand((60..80), inf) + ), + bufSize: 10, + lookBack: Pseq([0, 0, 0, 2, 2, 3, 3], inf) +).play +) + +p.stop + +:: + + +anchor::Ex.3a:: +subsection::Ex.3a: lookBack indices given as array + +code:: +// With the indices arg arbitrary series from the buffer can be played. +// Passing an array we define an index sequence which doesn't depend on lookBack + +( +~lookBack = 0; + +p = PSloop( + Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, Pseq((60..80), inf) + ), + bufSize: 10, + lookBack: { ~lookBack }, + indices: [0, 1, 0, 1, 2, 0, 1, 2, 3] +).trace.play +) + +// wait a bit to fill buffer +// start loop with useful lookBack (here > 3) + +~lookBack = 4 + +~lookBack = 6 + + +// go on and loop again + +~lookBack = 0; + +~lookBack = 5 + + +p.stop +:: + + +anchor::Ex.3b:: +subsection::Ex.3b: lookBack indices given as Function + +code:: +// If a Function is passed to indices it takes the current lookBack arg as argument. + +// mirroring the full lookBack size +// start without loop + +( +~lookBack = 0; + +p = PSloop( + Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, Prand((60..80), inf) + ), + bufSize: 10, + lookBack: { ~lookBack }, + indices: { |l| (0..l-1).mirror } +).trace.play +) + +// wait a bit to fill buffer +// mirrored loop i.e. loop with added retrograde + +~lookBack = 3 + + +// go on and loop again + +~lookBack = 0 + +~lookBack = 3 + +p.stop +:: + + +anchor::Ex.3c:: +subsection::Ex.3c: lookBack indices given as Pattern + +code:: +// The indices arg might get a pattern which can generate Functions as well as arrays. +// Start with sufficient number of zeros as lookBack to fill buffer. + +( +p = PSloop( + Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, Prand((60..80), inf) + ), + bufSize: 10, + lookBack: Pseq([Pn(0, 7), Pstutter(4, Pwhite(3, 5, 1))], inf).trace, + indices: Pseq([1!2, { |l| (l-1..0).postln }], inf).trace +).trace.play +) + +p.stop +:: + + +anchor::Ex.4a:: +subsection::Ex.4a: loopFunc given as Function + +code:: +// a Function passed to loopFunc is applied to all items of the looping + +( +~lookBack = 0; + +p = Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, PSloop( + Prand((60..80), inf), + bufSize: 10, + lookBack: { ~lookBack }, + loopFunc: { |x| x + [0, 5] } + ) +).play +) + +// wait a bit to fill buffer +// loop with Function applied + +~lookBack = 3 + +~lookBack = 6 + + +// go on and stop + +~lookBack = 0 + +p.stop +:: + + + +anchor::Ex.4b:: +subsection::Ex.4b: loopFunc given as Pattern + +code:: +// loopFunc also takes a pattern of Functions, in this case +// the arg loopFuncPerItem decides if next Functions are polled per item or per loop. + +( +~lookBack = 0; +~loopFuncPerItem = true; // or 1 + +p = Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, PSloop( + Prand((60..80), inf), + bufSize: 10, + lookBack: { ~lookBack }, + // every number gets a Function that adds an interval of that size + loopFunc: Pxrand((3..11), inf).collect { |x| { |y| y - [0, x].postln } }, + loopFuncPerItem: { ~loopFuncPerItem } + ) +).trace.play +) + +// wait a bit to fill buffer +// start looping with Functions polled per item + +~lookBack = 3 + +~lookBack = 6 + + +// one interval per loop + +~loopFuncPerItem = false // or 0 + +~lookBack = 9 + + +// switch back to new interval per item + +~loopFuncPerItem = 1 + + +// go on and stop + +~lookBack = 0 + +p.stop +:: + + +anchor::Ex.4c:: +subsection::Ex.4c: loopFunc vs. goFunc + +code:: +// Besides loopFunc a separate Function (or Pattern of Functions) can be defined for +// application outside loops via the goFunc arg. +// The arg loopFuncAsGoFunc decides if loopFunc should be taken for that task +// (and goFunc should be ignored in that case). + +( +~lookBack = 0; +~loopFuncPerItem = false; // one func per loop +~loopFuncAsGoFunc = false; // start with dedicated goFunc + +p = Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, PSloop( + Prand((60..80), inf), + bufSize: 10, + lookBack: { ~lookBack }, + // every number gets a Function that adds an interval of that size + loopFunc: Pxrand((3..11), inf).collect { |x| { |y| y - [0, x].postln } }, + loopFuncPerItem: { ~loopFuncPerItem }, + goFunc: { |x| [x, x + 2] }, + loopFuncAsGoFunc: { ~loopFuncAsGoFunc } + ) +).trace.play +) + +// wait a bit to fill buffer +// start looping with Functions polled per loop + +~lookBack = 3 + +~lookBack = 6 + + +// loop per item + +~loopFuncPerItem = true + + +// prepare to use loopFunc when going on + +~loopFuncAsGoFunc = true + + +// go on + +~lookBack = 0 + + +// switch to dedicated goFunc and stop + +~loopFuncAsGoFunc = false + +p.stop +:: + + + +anchor::Ex.4d:: +subsection::Ex.4d: Turning loopFunc and goFunc on and off + +code:: +// There are no separate PSloop flags needed for that: +// If loopFunc or goFunc return nil, no Function is applied, +// so suited Patterns using flags can be passed as loopFunc / goFunc args. + +( +~lookBack = 0; +~loopFuncPerItem = false; // one func per loop +~loopFuncAsGoFunc = false; // start with dedicated goFunc + +~turnOnLoopFunc = true; +~turnOnGoFunc = true; + +p = Pbind( + \dur, Pn(Pshuf([1, 1, 2]/6)), + \midinote, PSloop( + Prand((60..80), inf), + bufSize: 10, + lookBack: { ~lookBack }, + // every number gets a Function that adds an interval of that size, + // if ~turnOnLoopFunc evaluates to false the stream returns nil instead of a Function + loopFunc: Pxrand((3..11), inf).collect { |x| ~turnOnLoopFunc.if { { |y| y - [0, x].postln } } }, + loopFuncPerItem: { ~loopFuncPerItem }, + goFunc: Pfunc { ~turnOnGoFunc.if { { |x| [x, x + 2] } } }, + loopFuncAsGoFunc: { ~loopFuncAsGoFunc } + ) +).trace.play +) + +// wait a bit to fill buffer +// start looping with Functions polled per loop + +~lookBack = 3 + +~lookBack = 6 + + +// when Functions are polled per loop, turning loopFunc off also works per loop + +~turnOnLoopFunc = false + + +// use loopFunc again, namely per item + +~turnOnLoopFunc = true + +~loopFuncPerItem = true + + +// now turning it off works immediately + +~turnOnLoopFunc = false + + + +// go on + +~lookBack = 0 + + +// as loopFunc is now turned off, this applies also when used for new values + +~loopFuncAsGoFunc = true + + +// switch to goFunc again + +~loopFuncAsGoFunc = false + + +// silently turn loopFunc on + +~turnOnLoopFunc = true + + +// turn goFunc off and again use loopFunc as goFunc + +~turnOnGoFunc = false + +~loopFuncAsGoFunc = true + + + +// loop, again with loopFunc per item + +~lookBack = 5 + + +p.stop + +:: + + +anchor::Ex.5:: +subsection::Ex.5: PSloops controlling different sound params + +code:: +// Overlapping of loops on different sound params can give interesting polyrhythmic structures + +( +SynthDef(\psloop_1, { |out = 0, freq = 440, centDif = 5, rq = 0.1, cutoff = 1000, amp = 0.1 + att = 0.01, sus = 0.0, rel = 0.01| + var sig = Saw.ar(freq * [1, (centDif * 0.01).midiratio], amp); + Out.ar(0, BPF.ar(sig, cutoff.clip(30, 8000)) * EnvGen.ar(Env.linen(att, sus, rel), doneAction: 2)); +}, 0.01!6).add +) + +( +// Function to generate a standard PSloop with lookBack arg to by controlled by env variable with suffix LB +// Pfunc could also be written as: PL((name ++ \LB).asSymbol) + +~psLoop = { |src, name| PSloop(src, bufSize: 10, lookBack: Pfunc { currentEnvironment[(name ++ \LB).asSymbol] }) }; + +p = Pbind( + \instrument, \psloop_1, + \att, 0.01, + \amp, Pfunc { ~amp }, + \sus, ~psLoop.(Prand([0.1, 0.2], inf), \sus), + \rel, ~psLoop.(Prand([0.01, 0.1, 1], inf), \rel), + \dur, ~psLoop.(Pn(Pshuf([1, 1, 2]/5)), \dur), + \centDif, Pshuf([5, -20, 40], inf), + \midinote, ~psLoop.(Pxrand((30..50), inf), \midinote), + \cutoff, ~psLoop.(Pshuf([500, 1500, 5000], inf), \cutoff) +); + +q = Pbindf(p, \midinote, ~psLoop.(Pxrand((50..70), inf), \midinote)); +r = Pbindf(p, \midinote, ~psLoop.(Pxrand((75..95), inf), \midinote)); + + +// VarGui for control of lookBack params of 3 parallel streams +// zero values for args with suffix LB mean: no looping + +// play loops by setting several params to non-zero values, +// you can grab params of different voices by using the alt key while +// moving a slider + +VarGui({ |i| [ + \susLB, [0, 7, \lin, 1, 0], + \relLB, [0, 7, \lin, 1, 0], + \durLB, [0, 7, \lin, 1, 0], + \midinoteLB, [0, 7, \lin, 1, 0], + \cutoffLB, [0, 7, \lin, 1, 0], + \amp, [0, 1, \lin, 0, 0.2 + (i * 0.1)] +] }!3, stream: [r, q, p], quant: 1/5 +).gui(labelWidth: 80) +) +:: + diff --git a/HelpSource/Classes/PSrecur.schelp b/HelpSource/Classes/PSrecur.schelp new file mode 100644 index 0000000..689e132 --- /dev/null +++ b/HelpSource/Classes/PSrecur.schelp @@ -0,0 +1,117 @@ +CLASS:: PSrecur +summary:: Pattern to generate new values with a recursive Function +categories::Libraries>miSCellaneous>PSx stream patterns, Streams-Patterns-Events>PSx stream patterns +related:: Overviews/miSCellaneous, Tutorials/PSx_stream_patterns, Classes/MemoRoutine, Classes/PS, Classes/PSdup, Classes/PSloop + + + +CLASSMETHODS:: + +method::new + +Creates a new PSrecur object. + +argument::recurFunc +Recursive Function, the the array of last values will be passed as first arg, count as second arg. + +argument::length +Number of output items, may be pattern or stream, defaults to inf. + +argument::bufSize +Size of buffer to store last values. +If strong::bufSize:: is not defined and strong::start:: is not given or a single item, strong::bufSize:: gets value 1. +If strong::bufSize:: is not defined and strong::start:: is an array strong::bufSize:: gets its length. + +argument::start +Single start item or array of items used for recursion. + +argument::copyItems +Determines if and how to copy the last items generated by strong::recurFunc:: which are either non-Sets or member of Sets. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). +Other values are interpreted as 0. Defaults to 0. + +0: original item + +1: copy item + +2: deepCopy item + +argument::copySets +Determines if and how to copy Sets generated by strong::recurFunc::. +Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). +Other values are interpreted as 0. Defaults to 1. + +0: original Set + +1: copy Set + +note:: +The distinction of copying items and sets makes sense in the case of event streams. Per default Events are copied (strong::copySets:: == 1), not their values (strong::copyItems:: == 0). By playing Events those are used to store additional data (synth ids, msgFuncs …) which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use MemoRoutine - copied Events will not contain this additional data. If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured then copying makes no sense, this is the normal case, so copyItems defaults to 0. When going to alter the ouput, you might want to set strong::copyItems:: to 1 for a PSx returning simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set strong::copySets:: to 1 and strong::copyItems:: to 2 (an option strong::copySets:: == 2 doesn't exist as it would be contradictory in combination with strong::copyItems:: < 2). +:: + + +note:: +Copy options concern copying into PSrecur's buffer as well as the output of a Stream derived from the PSrecur. When such a Stream is outputting copies this prevents unintended altering of items stored in the buffer of PSrecur. On the other hand storing copies in PSrecur's buffer prevents these from being altered unintendedly. +:: + + +INSTANCEMETHODS:: + +method::recurFuncStream +Instance variable getter and setter methods. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// another way to generate the fibonacci sequence +// the first arg passed to the Function is the PSrecur itself, +// x[0] refers to its last value, x[1] to the value before the last value + +( +a = PSrecur({ |x| x[0] + x[1] }, start: [0, 1]); +b = a.iter; +b.nextN(10); +) + +// shorter with partial application + +PSrecur(_[0]+_[1], start: [0, 1]).iter.nextN(10); + + +// recursion with event patterns +// function calculates an iterated average of past event values for all keys, +// events at the end of the array are taken into account most. + +( +u = { |e,f| e.copy.keysValuesChange { |k| e[k]+f[k]/2 } }; +v = { |a| a.reduce(u) }; +) + +( +// three basic Events + +e = (midinote: 65, dur: 0.75, amp: 0.1, pan: 0); +f = (midinote: 58, dur: 0.05, amp: 0.3, pan: -1); +g = (midinote: 92, dur: 0.05, amp: 0.4, pan: 1); + +// mostly build "blurred" average of last five events, +// by chance disturbance by choosing a basic event + +p = PSrecur({ |x| 0.8.coin.if { v.(x[..4]) }{ [e,f,f,g].choose } }, start: [e,f,e,g,e]); + +q = p.trace.play; +) + +q.stop; + + +:: + diff --git a/HelpSource/Classes/PV_BinGap.schelp b/HelpSource/Classes/PV_BinGap.schelp new file mode 100755 index 0000000..3afc6a4 --- /dev/null +++ b/HelpSource/Classes/PV_BinGap.schelp @@ -0,0 +1,103 @@ +CLASS:: PV_BinGap +summary:: pseudo ugen keeping the complement of a spectral range +categories::Libraries>miSCellaneous>PV pseudo ugens +related:: Overviews/miSCellaneous, Classes/PV_BinRange, Guides/FFT-Overview + + +DESCRIPTION:: + + +Based on link::Classes/PV_BrickWall::, but instead of wipe parameters it takes two bin numbers. + + +CLASSMETHODS:: + +method::new + +Creates a new PV_BinGap object. + +argument::buffer +FFT buffer. + +argument::loBin +low bin index of excluded range. + +argument::hiBin +high bin index of excluded range. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// frequencies are rounded to nearest bins + +( +f = { |loFreq = 800, hiFreq = 1500, fundFreq = 50, amp = 0.1| + var bufSize = 1024, binRange, loBin, hiBin, sig, chain; + + sig = Saw.ar(fundFreq, amp); + + binRange = s.sampleRate / bufSize; + loBin = (loFreq / binRange).round; + hiBin = (hiFreq / binRange).round; + + chain = FFT(LocalBuf(bufSize), sig); + chain = PV_BinGap(chain, loBin, hiBin); + IFFT(chain) ! 2; +}; + +x = f.play; + +s.freqscope; +) + +x.set(\loFreq, 300); + +x.set(\hiFreq, 3000); + +x.release; + + + +// for multichannel expansion an array of mono buffers must be provided + +( +g = { |loFreq = 800, hiFreq = #[1500, 1500] fundFreq = 50, amp = 0.1| + var bufSize = 1024, binRange, loBin, hiBin, sig, chain; + + sig = Saw.ar(fundFreq, amp); + + binRange = s.sampleRate / bufSize; + loBin = (loFreq / binRange).round; + hiBin = (hiFreq / binRange).round; + + chain = FFT({ LocalBuf(bufSize) } ! 2, sig); + chain = PV_BinGap(chain, loBin, hiBin); + IFFT(chain); +}; + +x = g.play; + +s.freqscope; +) + +x.set(\loFreq, 300); + +x.set(\hiFreq, [1200, 1200]); + +x.set(\hiFreq, [800, 2000]); + +x.set(\hiFreq, [2000, 800]); + +x.release; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/PV_BinRange.schelp b/HelpSource/Classes/PV_BinRange.schelp new file mode 100755 index 0000000..a2a4390 --- /dev/null +++ b/HelpSource/Classes/PV_BinRange.schelp @@ -0,0 +1,103 @@ +CLASS:: PV_BinRange +summary:: pseudo ugen keeping a spectral range +categories::Libraries>miSCellaneous>PV pseudo ugens +related:: Overviews/miSCellaneous, Classes/PV_BinGap, Guides/FFT-Overview + + +DESCRIPTION:: + + +Based on link::Classes/PV_BrickWall::, but instead of wipe parameters it takes two bin numbers. + + +CLASSMETHODS:: + +method::new + +Creates a new PV_BinRange object. + +argument::buffer +FFT buffer. + +argument::loBin +low bin index of resulting range. + +argument::hiBin +high bin index of resulting range. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// frequencies are rounded to nearest bins + +( +f = { |loFreq = 800, hiFreq = 1500, fundFreq = 50, amp = 0.1| + var bufSize = 1024, binRange, loBin, hiBin, sig, chain; + + sig = Saw.ar(fundFreq, amp); + + binRange = s.sampleRate / bufSize; + loBin = (loFreq / binRange).round; + hiBin = (hiFreq / binRange).round; + + chain = FFT(LocalBuf(bufSize), sig); + chain = PV_BinRange(chain, loBin, hiBin); + IFFT(chain) ! 2; +}; + +x = f.play; + +s.freqscope; +) + +x.set(\loFreq, 300); + +x.set(\hiFreq, 1000); + +x.release; + + + +// for multichannel expansion an array of mono buffers must be provided + +( +g = { |loFreq = #[500, 500], hiFreq = 1500, fundFreq = 50, amp = 0.1| + var bufSize = 1024, binRange, loBin, hiBin, sig, chain; + + sig = Saw.ar(fundFreq, amp); + + binRange = s.sampleRate / bufSize; + loBin = (loFreq / binRange).round; + hiBin = (hiFreq / binRange).round; + + chain = FFT({ LocalBuf(bufSize) } ! 2, sig); + chain = PV_BinRange(chain, loBin, hiBin); + IFFT(chain); +}; + +x = g.play; + +s.freqscope; +) + +x.set(\loFreq, [200, 200]); + +x.set(\loFreq, [300, 1200]); + +x.set(\loFreq, [1200, 300]); + +x.set(\hiFreq, 2000); + +x.release; + +:: + \ No newline at end of file diff --git a/HelpSource/Classes/Pattern.ext.schelp b/HelpSource/Classes/Pattern.ext.schelp new file mode 100644 index 0000000..d4023b7 --- /dev/null +++ b/HelpSource/Classes/Pattern.ext.schelp @@ -0,0 +1,24 @@ + + + +INSTANCEMETHODS:: + + + +private:: miSC_repTypeFactor + +private:: miSC_streamifySieveItems + + +method:: asESP +Abbreviation for asEventStreamPlayer + +method::symplay + +Plays a pattern wrapped into a link::Classes/PsymNilSafe::. Args strong::clock::, strong::protoEvent:: and strong::quant:: are passed to link::Classes/Pattern#-play::, strong::dict:: and strong::maxNull:: work like with PsymNilSafe, strong::dict:: defaults to the current Environment and strong::maxNull:: to 128. See link::Tutorials/PLx_and_live_coding_with_Strings:: + + +method::eventShortcuts + +Wraps the receiver into a Pcollect with a Function that replaces according to EventShortcuts if it's turned on. This can be useful in cases where a pattern's method embedInStream changes keys of Events before applying the event type function, that employs the normal replacement mechanism of EventShortcuts. Then the mapping can be done inside/before. Normally you wouldn't need to call that method explicitely. See also link::Classes/EventShortcuts::, link::Classes/Event#-eventShortcuts::, link::Classes/SequenceableCollection#-eventShortcuts:: and link::Tutorials/PLx_and_live_coding_with_Strings:: + diff --git a/HelpSource/Classes/PbindFx.schelp b/HelpSource/Classes/PbindFx.schelp new file mode 100755 index 0000000..0cbaf9d --- /dev/null +++ b/HelpSource/Classes/PbindFx.schelp @@ -0,0 +1,2096 @@ +CLASS:: PbindFx +summary:: event pattern for effect handling on per-event base +categories:: Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/kitchen_studies, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PmonoPar, Classes/PpolyPar, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + + +DESCRIPTION:: + + +PbindFx works like a normal Pbind of event type 'note' in most regards, but with the additional option to define a number of effects. Their order and parameters can also be defined with patterns which allows a great flexibility: for each event an arbitrary multichannel effect graph can be applied, mixing sequential and parallel arrangement ad libitum. This requires a relatively high amount of resource management: bus allocation, routing and node ordering as well as delayed cleanup have to be done for each event. All necessary bookkeeping is done automatically, for some critical parameters though it's the user's responsibility to pass meaningful values (e.g. cleanupDelay for reverb has to be defined sufficiently high, otherwise reverb synth and audio bus might be freed before reverb has ended). There is always a tradeoff between flexibility and processing effort, if you won't change fx parameters on a per-event base or you won't reorder your effect arrangement, then you might prefer playing effects from and to predefined buses and control them otherwise, e.g. per LFOs (additionally possible also with PbindFx) or dedicated setting streams, see link::Classes/PmonoPar:: and link::Classes/PpolyPar::. However with the strategy of effects bound to buses you have the same effect arrangements and parameters concerning all source signals sent to the same bus, more variation with such setups needs more (pre-)definition of buses, whereas with PbindFx overlapping events can be processed with different effect arrangements and parameters with no explicit effort. +One possible application of PbindFx is applying effects per grain, for the project link::Tutorials/kitchen_studies:: I documented the source code of a fixed media piece in six parts, using this technique. + +warning:: + +As bus allocation is done dynamically per event, there is a circumvented, but still potential danger of creating feedback loops. To prevent this, additional "zero synths" are started with bus-reading fx synths, playing a zero signal with ReplaceOut to the buses in question, they are placed before those fx / source synth(s), which will play there too. For all test examples, even with deliberately bad values, zero synths turned out to be an effective way to block unwanted input signals and feedback, as they last as long as fx / source synths (they even overlap them a bit). However, with extraordinary parameter values for timing, improperly defined fx / source synths, sloppy audio bus mapping and / or parallel actions that affect resource management globally, feedback, as in any situation of heavy bus repatching, can not be totally excluded. Be aware of that, avoid high levels and be careful with headphones ! +:: + + + +CLASSMETHODS:: + +method::new + +Creates a new PbindFx object. + + +argument::pbindData +SequenceableCollection of Pbind's key/value pairs or event pattern. +Passing a list saves explicitely typing Pbind, but passing an event pattern is more flexible, +as it allows replacement (link::#Ex. 7#Ex.7::), event pattern filtering (link::#Ex. 3a#Ex.3a::) and similar operations. + +specific keys: + +list:: +## strong::\fxOrder:: – For each event it can be given in three ways, for single effects and +sequential ordering it may be + +numberedlist:: +## strong::an Integer::, or +## strong::a SequenceableCollection of Integers::, +indicating the effect order. Effect counting starts with 1, 0 means no effect (default). +E.g. if three effects are passed to strong::fxData::, [1], [2], [3], [1, 2], [1, 3], [2, 3], +[2, 1], [3, 1], [3, 2], [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1], +would represent all possible effect orders with each effect applied once. +Passing single Integers is equivalent to passing them in an array. +Data concerning one event can also be given as +## strong::a Ref object containing an IdentityDictionary::, representing the effect graph. +Keys of the dictionary – single Integers – are identified with effects of strong::fxData::, values +of the dictionary might be single Integers or SequenceableCollections of +Integers, indicating a branching of effects (whenever you want a branching of effects +or routing two different effects to a third one, the input must be given as a ref'd IdentityDictionary). +Within the effect graph an explicit direct out can be denoted with the Symbol \o, +0 represents the source. The graph must be acyclic, a check is performed. +strong::fxOrder:: can also be a Pattern, sequencing effect orders of the forms (1) - (3). +See link::#Principle of operation#Principle of operation:: and link::#Ex. 10a#Ex.10a::, link::#Ex. 10b#Ex.10b::, link::#Ex. 10c#Ex.10c::. +:: + +## strong::\cleanupDelay:: – Number or Pattern to generate Numbers, taken as seconds. +Its meaning differs, depending if source synth (passed by \instrument) has +a gated or fixed length envelope. If a gate control is encountered in the SynthDef +description, a gated envelope is assumed. +In the latter case this arg determines the earliest time after release when +cleanup may start. With a fixed-length envelope it determines the earliest time +after synth start when cleanup may start. +With effects defined, cleanupDelays of source and effects are summarized. +Defaults to the class variable strong::defaultSourceCleanupDelay:: which defaults to 0.3. +Typically you would take the releaseTime of the source synth's / synthdef's +gated envelope, or the maximum overall length of the fixed-length envelope, +each plus a small delta. + +## strong::\cleanupClock:: – The clock on which freeing of audio buses is scheduled with SkipJack objects. +As the clock should survive CmdPeriod its permanent flag must be set to true. +Per default the SystemClock is used, but for certain cases, e.g. granulation +you might want to pass a TempoClock with higher queueSize, see examples below. + +## strong::\cleanupDt:: – Number or Pattern to generate Numbers, taken as seconds. +Determines the delta time for cleanup with SkipJack objects. In those intervals +it is checked whether event-specific cleanup delaytimes have been reached +and cleanup (freeing buses) should be performed. Defaults to the class variable +strong::defaultCleanupDt:: which defaults to 0.2. With higher values more SkipJack objects +have to be scheduled at the same time, although with fewer activity. + +## strong::\freePerGroup:: – Boolean, defaults to false. +Determines if effects and zero synths of the chain should be freed separately or +removed at the end of the chain by freeing the enclosing group. +With more effects and longer cleanupDelays the latter leads to a larger number +of parallel synths and might be wasteful thus. On the other hand it can be +a useful option with short events and cleanupDelays, e.g. in case of granulation. +See below timing scheme for a more detailled description. + +## strong::\otherBusArgs:: – Takes SequenceableCollection of Symbols, defaults to nil. +For all passed symbols the source synth is enabled to read from and write to external buses, +which are passed to an arg of that name, LocalIn and LocalOut are allowed anyway. +Per default a restrictive check of synth I/O ugens and matching is performed in order to prevent +unintended reading from resp. writing to buses. With this option you can allow reading +and writing in a controlled way, see link::#Ex. 6a#Ex.6a:: and link::#Ex. 6b#Ex.6b::. + +:: + +argument::... fxData +SequenceableCollection of Pbind's key/value pairs defining effect sequencing or event pattern. +Passing a list saves explicitely typing Pbind, but passing an event pattern is more flexible, +as it allows replacement (link::#Ex. 7#Ex.7::), event pattern filtering (link::#Ex. 3a#Ex.3a::) and similar operations. + +specific keys: + +list:: +## strong::\fx:: – Symbol or Pattern to generate Symbols. +Determines the effect synthdef. + +## strong::\cleanupDelay:: – Number or Pattern to generate Numbers, taken as seconds. +Determines the earliest time after effect node delay when cleanup, +including freeing the effect synth, may start. +With effects defined, cleanupDelays of source and effects are summarized. +Defaults to the class variable strong::defaultFxCleanupDelay:: which defaults to 0.05. +Typically you would take the maximum delay of the effect synth plus a small delta. + +## strong::\otherBusArgs:: – Takes SequenceableCollection of Symbols, defaults to nil. +For all passed symbols the fx synth is enabled to read from and write to external buses, +which are passed to an arg of that name, LocalIn and LocalOut are allowed anyway. +Per default a restrictive check of synth I/O ugens and matching is performed in order to prevent +unintended reading from resp. writing to buses. With this option you can allow reading +in a controlled way, see link::#Ex. 6a#Ex.6a:: and link::#Ex. 6b#Ex.6b::. +:: + + +method::defaultSourceCleanupDelay + +Get and set the value of this class variable. Defaults to 0.3. + + +method::defaultCleanupDt + +Get and set the value of this class variable. Defaults to 0.2. + + +method::defaultFxCleanupDelay + +Get and set the value of this class variable. Defaults to 0.05. + + +anchor::Principle of operation:: +section::Principle of operation + +subsection::Per-event effect routing with PbindFx, example scheme of two effects applied sequentially + +This can typically be achieved by passing an array [i, j] to \fxOrder, where i and j denote arbitrary unequal positive effect numbers (numbers smaller or equal than strong::fxData::'s size). + +Fig. 1 + +image::attachments/PbindFx/PbindFx_graph_1.png:: + + +Effects FX#1 and FX#2 read from buses BUS#1 and BUS#2 which are reserved for the duration of the event plus a cleanup time. BUS#1 and BUS#2 get their data from source synth SRC resp. FX#1. "Zero synths" Z#1 and Z#2 are placed before them in node order, they are lasting as long as (in fact a bit longer than) FX#1 and FX#2, playing zero signals to BUS#1 and BUS#2 with ReplaceOut and cancelling out possible residual signals on those buses, thus blocking feedback. BUS#1 and BUS#2 might be multichannel buses, in that case a number of mono zero synths is established for each Z#i. +Two dedicated groups are generated for each event: FXGRP is the container for all event-generated synths and SRCGRP is placed at its head. Z#1 is placed at the head of SRCGRP, other zero synths and effects are sequentially placed upwards from the tail of FXGRP, interlaced in the way described below. Finally source synth(s) are placed at tail of SRCGRP (the group passed further to the note event). + + +node ordering for n = 2 + +Fig. 2 + +list:: +##FXGRP: +list:: + ##SRCGRP: +list:: + ##Z#1 + ##SRC +:: + + ##Z#2 + ##FX#1 + ##FX#2 +:: +:: + +You can also pass a group (or a pattern of groups) to PbindFx, in that case FXGRP is related to the group depending on \addAction (default \addToHead): + + + +general node ordering with n sequentially applied effects for n > 2 +group GRP passed to PbindFx with key \group, +default addAction \addToHead + + +Fig. 3 + +list:: +##GRP: +list:: + ##FXGRP: +list:: + ##SRCGRP: +list:: + ##Z#1 + ##SRC +:: + ##Z#2 + ##FX#1 + + ... + + ... + + ##Z#n + ##FX#n-1 + ##FX#n +:: +:: +:: + + +Note that effect order is arbitrary per event, determined by key strong::\fxOrder::, in these examples FX#i denote the order in the regarded event, not the order in which the effects are passed to PbindFx. The whole process is implemented via dedicated event type 'pbindFx', an extension of event type 'note', which is chosen with PbindFx by default. The following schemes refer to server-side timing, additional lang-side offset might be passed with lag (in seconds) to ensure proper timing for sequences combining delayed and non-delayed effects e.g. including occasional echo as in several of the examples below. + + +subsection:: Timing scheme of PbindFx with two effects applied sequentially, source synth with gated envelope + +Fig. 4 + +image::attachments/PbindFx/PbindFx_graph_2a.png:: + + +list:: +##t#0: start SRC, Z#i, FX#i and groups with server-side ordering as described in routing scheme, + in fact Z#i are started slightly earlier. +##t#1: begin of SRC envelope release period, caused by a release message (set gate arg to 0) +##t#2: end of SRC envelope release period, probably end of source synth (doneAction = 2) +##t#3: supposed latest end of source synth due to given cleanupDelay of source, added to t#1 + (cleanupDelay might be passed as a constant maximum release time for all events) +##t#4: list:: + ##~freePerGroup == false (default): freeing of FX#1 and Z#1, the latter a bit later + ##~freePerGroup == true: do nothing + :: +##t#5: free FXGRP, thus also FX#2 and Z#2. +:: + +For longer effect chains with n effects the case distinction of t#4 applies to all pairs Z#i / FX#i for 1 < i < n: +with ~freePerGroup == true they all are freed at last by freeing the group. + + +subsection:: Timing scheme of PbindFx with two effects applied sequentially, source synth with fixed-length envelope + +Fig. 5 + +image::attachments/PbindFx/PbindFx_graph_2b.png:: + + +list:: +##t#0: start SRC, Z#i, FX#i and groups with server-side ordering as described in routing scheme, + in fact Z#i are started slightly earlier. +##t#1: begin of SRC envelope release period, caused by the synth itself (no setting gate to 0) +##t#2: end of SRC envelope release period, probably end of source synth (doneAction = 2) +##t#3: supposed latest end of source synth due to given cleanupDelay of source, added to t#0 + (cleanupDelay might be passed as a constant maximum envelope length for all events) +##t#4 - t#5: as with gated envelope +:: + + +subsection:: Parallel effect processing, arbitrary effect graphs + +The most simple case of applying two effects in parallel can be triggered by passing `(0: [1, 2]) to fxOrder. Effect numbers occurring in arrays of dictionary values cause a routing from these effects to out. Symbol \o (for destination out) can also be passed explicitely. +Branching like this requires the use of a split synth which routes the output to the demanded multitude of fx buses. A suitable predefined split synthdef is chosen according to the number of branches and the channel number of the signal to be splitted – currently both is limited by 8, however synths, which are only playing to out directly, might have an arbitrary number of output channels. +Different to sequential fx processing, both fx bus zero synths have to be added before the source, additional zero synth(s) for the split bus are prepended. + +Fig. 6 + +image::attachments/PbindFx/PbindFx_graph_3a.png:: + +The following effect graph can be established by fxOrder `(0: [1, 2, 3], 2: [4, \o], 3: 2), split synths, zero synths (for fx buses and split buses) are omitted in this scheme. For each (acyclic) fx graph a topological order is calculated (here it could e.g. be [0,1,3,2,4]) and the node ordering, including FXGRP and SRCGRP, similar to the sequential case, is derived accordingly. Some small differences, especially concerning the cleanup delay times, have to be taken into account, these details are omitted here. + +Fig. 7 + +image::attachments/PbindFx/PbindFx_graph_3b.png:: + + +section::Conventions + +numberedlist:: + +##Source instrument and effect SynthDefs must be known to SynthDescLib.global (e.g. by creating SynthDefs with methods 'add' or 'store') + +##Fx SynthDefs must be defined with arg 'out' for the outbus index, arg 'in' for inbus index and use In.ar(in, ...) within the SynthDef.It's up to the user whether to define the effect with dry/wet mix option. Effect synths don't need to have an envelope, their freeing is handled by the event type function. + +##Effect chains must be defined properly in terms of in/out channel number. For each event the bus matching of the effect chain is checked, following these conventions: + +list:: +##For source and fx SynthDefs there must be only one out ugen using 'out' as bus arg, LocalOut is allowed, other out ugens can be admitted by strong::\otherBusArgs::. +##Source SynthDefs must not have in ugens, except LocalIn or they are admitted by strong::\otherBusArgs::. +##Fxs must read from buses with ugen In.ar(in, ...) refering to the bus arg 'in', there must not be other in ugens within the fx SynthDef except LocalIn or they are admitted by strong::\otherBusArgs::, see link::#Ex. 6a#Ex.6a:: and link::#Ex. 6b#Ex.6b::. +##Number of out channels of preceeding source / fx synth must not be greater than the number of the following fx synth's in channels, this is checked for all pairs of an fx graph. +##Mismatches of above points lead to errors. +:: + +##Checks of (3) are also based on info in SynthDescLib.global. It is possible to replace SynthDefs on the fly (link::#Ex. 7a#Ex.7a::, link::#Ex. 7b#Ex.7b::), in that case I'd recommend to use also methods 'add' or 'store' – e.g. in case of using 'send' for redefinition no bus matching check is performed and a possibly wrong routing would be undetected. + +##As shown in above graphics the source synth's cleanupDelay is interpretated differentely with gated and non-gated (fixed-length) envelopes. This is done automatically by looking for a 'gate' arg in the SynthDef's SynthDesc. It's the users responsibility to use the conventional arg 'gate' for release in the SynthDef and omit a 'gate' arg with SynthDefs employing fixed-length envelopes. + +##As with normal event patterns the source Pbind / Pbind pairs may be defined with arrays to produce multiple synths per event, then the whole source signal is routed to the fx graph (see link::#Ex. 2b#Ex.2b::, link::#Ex. 2c#Ex.2c:: and others). fxData pairs can also be defined with arrays, which causes parallel processing per node ("implicit parallelism"), see link::#Ex. 4#Ex.4a::. For applying different fxs to parallel events (resp. chords) use parallel PbindFxs (link::#Ex. 3a#Ex.3a::, link::#Ex. 3b#Ex.3b::). It is of course also possible that fx synths have array args and fx patterns are passing them with the double-bracketing convention used for these cases, see link::Tutorials/Event_patterns_and_array_args::. + +##Source instrument and effect SynthDefs are allowed to have args of same name. There is no problem as key/value pairs are stored in separate lists/events. + +##PbindFx is implemented per automatically chosen effect type 'pbindFx', which employs event type 'note', thus an event type must neither be passed to pbindData nor to fxData. + +##The value conversion framework can be used for fxData, e.g. by passing \midinote instead of \freq or \db instead of \amp as with Pbind, see Ex.9. Other than with Pbind, freq and amp event defaults are not passed to fx synths, if no such values are passed via fxData. In that case default values of fx synths are taken. + +##While playing PbindFx you should not play with allocation affecting private buses. Freeing buses is done by SkipJack objects, so you should not forcefully stop all SkipJack objects while playing PbindFx. + +##Keys \group and \addAction may be passed, they determine how the group enclosing event-generated synths is related to the passed group, see scheme link::#Principle of operation#Principle of operation::. + +##Zero synths are using the SynthDefs 'pbindFx_zero' and 'pbindFx_splitZero' which are written to disk at startup time, as well as split synths pbindFx_split_axb for a = 2,...,8 and b = 1,...,8. Of course these SynthDefs shouldn't be deleted or exchanged. + +:: + + +section::Resources, troubleshooting + +numberedlist:: + +##You might encounter the error message "Meta_Bus:audio: failed to get an audio bus allocated." As audio buses for effect chains are allocated and freed per event a higher number of private audio buses is likely to be required (more than default 128). You might also encounter the error message "exception in real time: alloc failed, increase server's memory allocation (e.g. via ServerOptions)". Hence it's recommended to set the concerned server options before (re-)booting and working with PbindFx, e.g.: + +code:: + +( +s.options.numPrivateAudioBusChannels = 1024; +s.options.memSize = 8192 * 16; +s.reboot; +) +:: + +##You might encounter the warning "Scheduler queue is full." Per default delayed freeing of buses is scheduled on SystemClock, which defaults to queueSize 1024. In case of granulation and/or large cleanup delays it's recommended to pass a cleanup clock with sufficiently large queueSize via strong::pbindData::, its permanent flag must be set to true, e.g.: + +code:: +... +\cleanupClock, t = TempoClock(queueSize: 8192).permanent_(true) +... +:: + +Note that this clock keeps on running and survives CmdPeriod, you should explicitely stop it if you don't need it anymore, hence it should be stored in a variable. In case you haven't done that you can still stop all TempoClocks and remove them from CmdPeriod with + +code:: +TempoClock.all.copy.do(_.stop) +:: + +##Cleanup delays for source and effects (or, if not passed, their default values) should be sufficiently large (see description of strong::\cleanupDelay:: ), otherwise effects and audio buses might be freed too early and signals cut. + +##Some effects, like echo, introduce a delay. If sequencing mixes delayed events with non-delayed events, entries of the latter have to be delayed accordingly to preserve correct timing, this can be done by setting an offset in seconds with \lag. See examples with echo below. +:: + +section::Ex. 1: Straight usage with unchanged effect order + +anchor::Ex. 1a:: +subsection::Ex. 1a: Source synth with sustained envelope + + +code:: +// boot server with extended resources + +( +s.options.numPrivateAudioBusChannels = 1024; +s.options.memSize = 8192 * 16; +s.reboot; +) + +// basic source and effect synthdefs for this help file + +( +// All ins and outs use two channels + +// source synthdef +// take releaseTime = decayTime + +SynthDef(\source, { |out = 0, freq = 400, decayTime = 0.5, + attackTime = 0.005, amp = 0.1, gate = 1| + var env, sig = Decay.ar(Impulse.ar(0), decayTime, Saw.ar(freq)); + env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2); + Out.ar(out, sig ! 2 * env) +}).add; + + +// spat fx +// This effect introduces a very small delay, +// in examples balancing by lag (as it obviously has to be done with echo) is neglected. + +SynthDef(\spat, { |out, in, freq = 1, maxDelayTime = 0.005, + amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = DelayC.ar( + inSig, + maxDelayTime, + { LFDNoise3.ar(freq, maxDelayTime, maxDelayTime/2) } ! 2, + amp + ); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + + +// echo fx, always unified delay maxEchoDelta + +SynthDef(\echo, { |out, in, maxEchoDelta = 0.2, echoDelta = 0.1, + decayTime = 1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = DelayL.ar( + CombL.ar(inSig, maxEchoDelta, echoDelta, decayTime, amp), + maxEchoDelta, + maxEchoDelta - echoDelta + ); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + + +// wah-wah fx + +SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000, + cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = RLPF.ar( + inSig, + LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi), + rq, + amp + ).softclip; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + + +// reverb fx +// rough estimation: freeVerb's room arg = decayTime / 10 + +SynthDef(\reverb, { |out, in, damp = 0.5, + decayTime = 10, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + Out.ar(out, FreeVerb.ar(inSig, mix, min(decayTime, 10) / 10, damp, amp)); +}).add; +) + + +// Fx params are sequenced on a per-event base. + +// see server window: number of groups (divided by 2) indicates +// the number of parallel event chains in action +// check while running with s.queryAllNodes + +( +p = PbindFx([ + \instrument, \source, + \dur, 0.25, + \amp, 0.2, + \midinote, Prand([ + Pwhite(80, 90, 1), + Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf), + ], inf), + + \fxOrder, [1, 2], + // With a sustained envelope \cleanupDelay refers to the maximum release time, + // in SynthDef \source releaseTime = decayTime, so take cleanupDelay = decayTime + \decayTime, Pwhite(0.2, 2), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + // oscillation of delay -> frequency modulation of source signal + \freq, Prand([1, 2, 3], inf), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + // variation by sequencing of params + \fx, \wah, + \mix, Pseq([0.2, 0.5, 0.7], inf), + \cutOffMoveFreq, Pseq([1, 2, 5, 10], inf), + \cleanupDelay, 0.01 + ] +); + +q = p.play; +) + +// see server window and compare "regular" stop +// (descending number of groups, synths and ugens reflects delayed cleanup) +// with stopping the same example by Cmd-Period + +q.stop; + +:: + + + +anchor::Ex. 1b:: +subsection::Ex. 1b: Source synth with fixed-length envelope + + +SynthDefs from link::#Ex. 1a:: plus SynthDef variation with adsr args + +code:: +( +SynthDef(\source_adsrFixed, { |out = 0, freq = 400, decayTime = 0.5, + att = 0.005, dec = 0.01, sus = 0.2, rel = 0.3, susLevel = 0.5, amp = 0.1| + var env, sig = Saw.ar(freq); + env = EnvGen.kr(Env([0, 1, susLevel, susLevel, 0], [att, dec, sus, rel]), doneAction: 2); + Out.ar(out, sig ! 2 * env * amp) +}).add; +) + +// adsr values passed, \cleanupDelay estimated as max of sum + +( +p = PbindFx([ + \instrument, \source_adsrFixed, + \dur, 0.25, + \att, Pwhite(0.005, 0.01), + \dec, Pwhite(0.01, 0.02), + \sus, Pwhite(0.02, 0.3), + \rel, Pwhite(0.2, 1.5), + + \susLevel, 0.4, + \amp, 0.2, + + \midinote, Prand([ + Pwhite(80, 90, 1), + Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf), + ], inf), + + \fxOrder, [1, 2], + + // cleanupDelay must be larger than max env length, otherwise events might be cut ! + // here we do an estimation (att + dec + sus + rel < 2), + // but it could be summed from those event values too, e.g. with + // \cleanupDelay, Pfunc { |e| e.att + e.dec + e.sus + e.rel } + \cleanupDelay, 2 + ],[ + \fx, \spat, + \freq, Prand([1, 2, 3], inf), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \wah, + \mix, Pseq([0.2, 0.5, 0.7], inf), + \cutOffMoveFreq, Pseq([1, 2, 5, 10], inf), + \cleanupDelay, 0.01 + ] +); + +q = p.play; +) + + +// check node order while running + +s.queryAllNodes; + +q.stop; +:: + + +section::Ex. 2: Sequencing of different effect chains + +anchor::Ex. 2a:: +subsection::Ex. 2a: Determined fx sequence + +PbindFx using spat and echo effects. Especially relevant keys: \fxOrder which determines fx sequencing and \cleanupDelay for proper releaseTimes of source and effects. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +p = PbindFx([ + \instrument, \source, + \dur, 0.5, + \amp, 0.3, + \midinote, Pwhite(50, 90), + + // fx sequence \spat, \spat + \echo, etc. + \fxOrder, Pseq([1, [1,2]], inf), + + // echo is delayed (maxEchoDelta = 0.2), + // compensate here by shift when no echo + // we need \lag rather than \timingOffset as the whole delaytime calculation refers to seconds + \lag, Pseq([0.2, 0], inf), + + // in SynthDef \source releaseTime = decayTime, so take cleanupDelay = decayTime + \decayTime, Pseq([1, 0.1], inf), + \cleanupDelay, Pkey(\decayTime) + ],[ + // define effect with index 1 + \fx, \spat, + \maxDelayTime, 0.005, + + // oscillation of delay -> frequence modulation of source signal + \freq, Pseq([1, 1, 10], inf), + + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + // define effect with index 2 + \fx, \echo, + \echoDelta, 0.08, + \decayTime, Pwhite(0.8, 3), + + \cleanupDelay, Pkey(\decayTime) + ] +); + +q = p.play; +) + +q.stop; +:: + +anchor::Ex. 2b:: +subsection::Ex. 2b: Random fx sequence + +If more than one synth per event is produced (here by key 'midinote'), the effect chain is applied to all of them, see link::#Ex. 3#Ex.3:: for applying different effects to parallel synths. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +p = PbindFx([ + \instrument, \source, + \dur, 0.2, + \amp, 0.3, + + // downwards tendency + chord sequence + \midinote, Pseq((90, 80..50), inf) + + Pn(Pshuf([[0, 5], 0, [0, 2.5], [-2.5, 12.5], [-3, 0]])), + + \fxOrder, Prand([1, [1,2], [1,2]], inf), + + // lag must be adapted to maxEchoDelta + \lag, Pfunc { |e| e.fxOrder.isArray.if { 0 }{ 0.2 } }, + + // echo -> shorter source decay + \decayTime, Pfunc { |e| e.fxOrder.isArray.if { 0.1 }{ 0.7 } }, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, Pseq((1..5)/50, inf), + \decayTime, 1, + \cleanupDelay, Pkey(\decayTime) + ] +); + +q = p.play; +) + +q.stop; +:: + + +anchor::Ex. 2c:: +subsection::Ex. 2c: Some extensions + +Additional use of rests, reverb added. Here the reverb usage is deliberately wasteful, see link::#Ex. 2d#Ex.2d:: for an alternative. The use of Pn + Pshuf (or equivalently Pshufn) gives balanced random variation for several key streams. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +p = PbindFx([ + \instrument, \source, + \dur, Pn(Pshuf(0.2!5 ++ Rest(0.2))), + + \midinote, Pseq((90, 80..40), inf) + + Pn(Pshuf([[0, 5], 0, [0, 2.5], [-2.5, 12.5], [-3, 0]])), + + \fxOrder, Pn(Pshuf([[1,2], [1,2,3], [3,1], 1])), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, Pfunc { |e| (e.fxOrder != [1,2]).if { 0.3 }{ 0.6 } }, + + \decayTime, Pfunc { |e| + rrand(0.3, 0.8) / (e.fxOrder.asArray.includes(2).if { 10 }{ 1 }) + }, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, Pn(Pshuf([1, 1, 1, 5, 20, 50])), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, Pseq((1..5)/50, inf), + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \reverb, + \mix, 0.3, + \damp, 0.1, + \decayTime, Pwhite(3.0, 10), + \cleanupDelay, Pkey(\decayTime) + ] +); + +q = p.play; +) + +q.stop; +:: + +anchor::Ex. 2d:: +subsection::Ex. 2d: Saving resources + +If effects have a long cleanup delay, you will get a possibly large number of overlapping effect chains. E.g. in link::#Ex. 2c#Ex.2c:: many reverb synths can be there in parallel, the decayTime is controlled by Pwhite(3.0, 10), so it might well be that reverbs with decayTimes 7.95, 8, and 8.1 are instantiated in parallel, which doesn't make much difference and is quite wasteful. Reverb is often placed at the last position of the effect chain, so a more efficient approach would be the following: do all effect sequencing without reverb with PbindFx and pipe the overall out to a permanently running reverb. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + + +code:: + +// start two reverbs with different parameters, read from dedicated buses + +( +a = Bus.audio(s, 2); +b = Bus.audio(s, 2); + +x = Synth(\reverb, [mix: 0.3, damp: 0.1, decayTime: 3, in: a]); +y = Synth(\reverb, [mix: 0.2, damp: 0.1, decayTime: 10, in: b]); +) + +// play PbindFx +// compare CPU usage with Ex. 2c + +( +p = PbindFx([ + \instrument, \source, + \dur, Pn(Pshuf(0.2!5 ++ Rest(0.2))), + + \midinote, Pseq((90, 80..40), inf) + + Pn(Pshuf([[0, 5], 0, [0, 2.5], 0, [-2.5, 12.5], [-3, 0]])), + + \fxOrder, Pn(Pshuf([1, 2, [1,2]])), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, Pfunc { |e| (e.fxOrder != [1,2]).if { 0.3 }{ 0.6 } }, + + \decayTime, Pfunc { |e| + rrand(0.3, 0.8) / (e.fxOrder.asArray.includes(2).if { 10 }{ 1 }) + }, + \cleanupDelay, Pkey(\decayTime), + + // pipe out to different reverbs resp. 0 (no reverb) + \out, Pn(Pshuf([0, 0, a, a, b])) + ],[ + \fx, \spat, + \freq, Pn(Pshuf([1, 1, 1, 5, 20, 50])), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, Pseq((1..5)/50, inf), + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) + ] +); + +q = p.play; +) + +// stop + +q.stop; + +// free extra resources + +[x, y, a, b].do(_.free); + +:: + + +anchor::Ex. 3:: +section::Ex. 3: Different effects for parallel synths + + +This can be done with parallel PbindFxs. + + +anchor::Ex. 3a:: +subsection::Ex. 3a: Using a template Pbind + + +Here the option of passing a source Pbind instead of a list of Pbind pairs can be used. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// master pattern, fxOrders defines fxOrder for voices of chord +f = Pbind( + \dur, 0.3, + \type, \rest, + \fxOrders, Pn(Pshuf([ + [[1, 3], 2, 1], [1, [1, 3], 2], [2, 1, [1, 3]], + [0, 1, 1], [1, 0, 1], [1, 1, 0] + ]).collect { |o| ~o = o }) +); + +// core source Pbind +a = Pbind( + \instrument, \source, + \dur, 0.3, + + // reference to fxOrder will be got from Pchains below + \lag, Pfunc { |e| e.fxOrder.includes(2).if { 0 }{ 0.2 } }, + \amp, Pfunc { |e| e.fxOrder.any([2,3].includes(_)).if { 0.3 }{ 0.1 } }, + + \decayTime, Pfunc { |e| rrand(0.5, 0.7) / (e.fxOrder.includes(2).if { 10 }{ 1 }) }, + \cleanupDelay, Pkey(\decayTime) +); + +// lists of fx pairs +b = [[ + \fx, \spat, + \freq, Pn(Pshuf([1, 2, 3, 10])), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) +],[ + \fx, \echo, + \echoDelta, 3/50, + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) +],[ + \fx, \wah, + \mix, 0.5, + \cutOffMoveFreq, Pseq([5, 10], inf), + \cleanupDelay, 0.01 +]]; + +// derive three Pchains from core Pbind, +// voice-specific fxOrder will be read from master pattern +u = a <> Pbind( + \fxOrder, Pfunc { ~o[0].asArray }, + \midinote, 72 +); + +v = a <> Pbind( + \fxOrder, Pfunc { ~o[1].asArray }, + \midinote, Pstutter(Pwhite(5, 10), Prand((60..70), inf)) +); + +w = a <> Pbind( + \fxOrder, Pfunc { ~o[2].asArray }, + \midinote, Pstutter(Pwhite(5, 10), Prand((75..85), inf)) +); + + +// play in parallel, master must be before + +d = 0.001; + +q = Ptpar([ + 0, f, + d, PbindFx(u, *b), + d, PbindFx(v, *b), + d, PbindFx(w, *b) +]).play; +) + +q.stop; + +:: + + +anchor::Ex. 3b:: +subsection::Ex. 3b: Using a PbindFx generator Function + +Equivalent to link::#Ex. 3a#Ex.3a::, but might look more straight, as fxOrder pair already generated with PbindFx Function. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// master pattern for fxOrder +f = Pbind( + \dur, 0.3, + \type, \rest, + \fxOrders, Pn(Pshuf([ + [[1, 3], 2, 1], [1, [1, 3], 2], [2, 1, [1, 3]], + [0, 1, 1], [1, 0, 1], [1, 1, 0] + ]).collect { |o| ~o = o }) +); + +// PbindFx generator + +g = { |i| PbindFx([ + \instrument, \source, + \dur, 0.3, + + \fxOrder, Pfunc { ~o[i].asArray }, + \lag, Pfunc { |e| e.fxOrder.includes(2).if { 0 }{ 0.2 } }, + \amp, Pfunc { |e| e.fxOrder.any([2,3].includes(_)).if { 0.3 }{ 0.1 } }, + + \decayTime, Pfunc { |e| rrand(0.5, 0.7) / (e.fxOrder.includes(2).if { 10 }{ 1 }) }, + \cleanupDelay, Pkey(\decayTime), + ],[ + \fx, \spat, + \freq, Pn(Pshuf([1, 2, 3, 10])), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, 3/50, + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \wah, + \mix, 0.5, + \cutOffMoveFreq, Pseq([5, 10], inf), + \cleanupDelay, 0.01 + ] +); +}; + +// derive three Pbindfs from PbindFx generator, +// as PbindFx is a subclass of Pbind, you can apply Pbindf as to Pbind + +u = Pbindf(g.(0), \midinote, 72); +v = Pbindf(g.(1), \midinote, Pstutter(Pwhite(5, 10), Prand((60..70), inf))); +w = Pbindf(g.(2), \midinote, Pstutter(Pwhite(5, 10), Prand((75..85), inf))); + +d = 0.001; +q = Ptpar([0, f, d, u, d, v, d, w]).play; +) + +q.stop; +:: + + +anchor::Ex. 4:: +section::Ex. 4: Applying the same fx SynthDef more than once in a chain + +subsection::Ex. 4a: Implicit duplication (= implicit parallelism) + +code:: +// Within a graph node parallelism can be established in analogy to +// the generation of multiple synths with Pbind: +// by passing an array as value within fxData. + +( +// pitchshift fx, result can easily be controlled by ear + +SynthDef(\pitchShift, { |out, in, windowSize = 0.2, midiShift = 1, + pitchDispersion = 0, timeDispersion = 0, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + + sig = PitchShift.ar( + inSig, + windowSize, + midiShift.midiratio, + pitchDispersion, + timeDispersion + ); + + Out.ar(out, (1 - mix) * inSig + (sig * mix) * amp); +}).add; + + + +p = PbindFx([ + \instrument, \source, + \dur, 0.5, + \amp, 0.2, + \midinote, Pwhite(50, 80), + + \fxOrder, 1, + // With a sustained envelope \cleanupDelay refers to the maximum release time, + // in SynthDef \source releaseTime = decayTime, so take cleanupDelay = decayTime + \decayTime, 1.5, + \cleanupDelay, Pkey(\decayTime) + ],[ + // variation by sequencing of params + \fx, \pitchShift, + \mix, 0.8, + // implicitely generate parallel processing with different fx params + // the two fxs applied in parallel together with the source result in a sequence of major triads + \midiShift, [4, 7], + \windowSize, 0.04, + \timeDispersion, 0.005, + \cleanupDelay, 0.01 + ] +); + +q = p.play; +) + +q.stop; +:: + + +subsection::Ex. 4b: Explicit duplication + +code:: +// By passing the same fx in different fxData args you have all options +// by defining the fx graph: in sequence, in parallel or however. +// Here is an example for explicit duplication in sequence, +// for defining explicit parallelism and arbitrary fx graphs see Ex. 10 + +// SynthDefs from Ex. 1a, see also extended server resources defined there + +( +p = PbindFx([ + \instrument, \source, + \dur, 1/3, + \amp, Pseq([0.2, 0.4, 0.3], inf), + \midinote, Pseq([ + Pwhite(35, 48, 1) + [-14, 0, 14], + Pshuf([60, 67, 70, 73], 1) + Pshuf([0, 12], 1) + [0, 4, 12], + ], inf), + + \fxOrder, Pseq([1, [1, 2], [1, 2, 3]], inf), + \lag, Pseq([0.17, 0.03, 0.00], inf), + + \decayTime, Pseq([2.5, 0.1, 0.1], inf), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, Prand([1, 2, 3], inf), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, Pwhite(0.06, 0.1), + \decayTime, 1, + + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \echo, + // short delta results in additional frequency + \echoDelta, Pwhite(0.005, 0.01), + \decayTime, 0.2, + + \cleanupDelay, Pkey(\decayTime) + ] +); + +q = p.play; +) + +q.stop; +:: + + + +anchor::Ex. 5:: +section::Ex. 5: Tempo control + +Tempo control works as with Pbind and can be influenced by a number of parameters. As cleanup parameters of PbindFx are passed in seconds, tempo control can be done independent from making cleanup time changes (though you might do so as well). The use of a dedicated TempoClock as master tempo control is a good idea, setting tempo for individual streams can be done with 'stretch'. The following example employs a PbindFx generator Function, the tempo of streams can be controlled individually and generally. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// PbindFx generator Function, +// streams will get different midinote offsets, +// tempo will be read from a passed array + +g = { |midiOffset, tempoArray, index| + + PbindFx([ + \instrument, \source, + \dur, 0.25, + \stretch, Pfunc { 1 / tempoArray[index] }, + \midinote, Prand([ + Pwhite(55, 75, 1), + Pn(Pshuf([60, 67, 70, 73])), + ], inf) + midiOffset, + + \fxOrder, Pn(Pshuf([1, 1, [1, 2], [1, 3]])), + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, 0.2, + + \decayTime, Pfunc { |e| rrand(0.3, 0.8) / (e.fxOrder.asArray.includes(2).if { 10 }{ 1 }) }, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, 2, + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, Pseq((1..5)/50, inf), + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \wah, + \mix, 0.5, + \resLo, 400, + \reHi, 2000, + \cutOffMoveFreq, 10, + \cleanupDelay, 0.01 + ] +) }; + +// master TempoClock + +t = TempoClock.new; + + +// array for individual tempo factors + +~tempo = [1, 1, 2]/2; + +// start first player on quant grid, +// it refers to the tempo factor ~tempo[0] +// note that quant refers to the tempo of the TempoClock + +x = g.(-24, ~tempo, 0).play(t, quant: 1); +) + +// start other players on quant grid + +y = g.(0, ~tempo, 1).play(t, quant: 1); + +z = g.(12, ~tempo, 2).play(t, quant: 1); + + +// change player's individual tempos, +// note that tempo changes do not necessarily happen on quant grid, +// so a rhythmic "phase shift" (which can be nice) might happen + +~tempo[2] = 2/3 + +~tempo[1] = 1/3 + +~tempo[0] = 1 + + +// set general tempo + +t.tempo = 3/4 + + +// stop players individually + +x.stop; + +y.stop; + +z.stop; + + +// stop clock + +t.stop; +:: + + +anchor::Ex. 6:: +section::Ex. 6: Further external routing + + +This means the use of buses, which are not internally used by PbindFx's event Function. As shown in link::#Ex. 2d#Ex.2d:: it can be useful to route PbindFx's out to an external reverb. Vice versa data can be read from external buses, from source synths as well as from fx synths. + +Audio routing benefits from the possibility to pass groups to PbindFx. Then all temporary groups, generated during playing the PbindFx, +are enclosed by it and node order can be clearly defined. For audio bus routing better use In.ar than mapping with asMap, that way matching of ins and outs of fx chains is checked and it avoids issues with using asMap and stopping the external source (occuring at least in SC 3.6.6). + +Spat SynthDef from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +anchor::Ex. 6a:: +subsection::Ex. 6a: Source synth reading audio modulation signals from external buses + +code:: +// source synth based on SinOsc and additional ring modulation, +// while reading from an audio bus with no signal, it outputs only the sine + +( +SynthDef(\source_mod, { |out = 0, freq = 400, decayTime = 0.5, + attackTime = 0.005, amp = 0.1, modIn, gate = 1| + var env, sig; + sig = Decay.ar(Impulse.ar(0), decayTime, SinOsc.ar(freq) * (1 + In.ar(modIn))); + env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2); + Out.ar(out, sig ! 2 * env) +}).add; +) + + +( +// new group and bus for the modulation signal +g = Group.new; +a = Bus.audio(s, 1); + +// play source with spat effect only +p = PbindFx([ + \instrument, \source_mod, + \dur, 0.25, + \amp, 0.1, + \midinote, Prand([ + Pwhite(80, 90, 1), + Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf), + ], inf), + + \fxOrder, 1, + + \modIn, a, + // to enable this reading the fx chain check must know + \otherBusArgs, [\modIn], + \group, g, + + \decayTime, Pwhite(0.2, 2), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, Prand([1, 2, 10], inf), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ] +); + +q = p.play; +) + + +// while playing PbindFx, play modulation synth to dedicated bus, +// placing before group ensures that all generated synths can read from the bus + +x = { Out.ar(a, SinOsc.ar(500, 0, 0.5)) }.play(target: g, addAction: \addBefore); + +// no modulation again + +x.free; + + +// modulation with other signal + +y = { Out.ar(a, Pulse.ar(700, 0.5, 0.5)) }.play(target: g, addAction: \addBefore); + + +// add a further modulation signal + +z = { Out.ar(a, Formant.ar(700, 1200, mul: 0.5)) }.play(target: g, addAction: \addBefore); + + +// formant modulation only + +y.free; + +// stop it also + +z.free; + + +// stop and PbindFx cleanup + +q.stop; + + +// cleanup of other resources, free bus and group + +( +g.free; +a.free; +) +:: + +anchor::Ex. 6b:: +subsection::Ex. 6b: Fx synths reading audio modulation signals from external buses + +Spat SynthDef from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// simple sine source synth +SynthDef(\source_sine, { |out = 0, freq = 400, decayTime = 0.5, + attackTime = 0.005, amp = 0.1, gate = 1| + var env, sig; + sig = Decay.ar(Impulse.ar(0), decayTime, SinOsc.ar(freq)); + env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2); + Out.ar(out, sig ! 2 * env) +}).add; + +// ring modulation fx synth, expecting to read the modulation signal from a bus +SynthDef(\ring, { |out, in, modIn, amp = 2, mix = 0.5| + var sig, inSig = In.ar(in, 2); + sig = inSig * In.ar(modIn, 1); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; +) + +( +// new group and buses for the modulation signal +g = Group.new; + +a = Bus.audio(s, 1); +b = Bus.audio(s, 1); + +// two ring modulation fxs +p = PbindFx([ + \instrument, \source_sine, + \dur, 0.25, + \amp, 0.12, + \midinote, Prand([ + Pwhite(80, 90, 1), + Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf), + ], inf), + + \group, g, + + \fxOrder, Pn(Pshuf([1, [1, 2], [1, 3]])), + \decayTime, Pwhite(0.2, 2), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, Prand([1, 2, 10], inf), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \ring, + // need the index explicitely here + \modIn, a.index, + // to enable this reading the fx chain check must know + \otherBusArgs, [\modIn], + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \ring, + \modIn, b.index, + // to enable this reading the fx chain check must know + \otherBusArgs, [\modIn], + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ] +); + +q = p.play; +) + + +// now live change of modulation as in Ex. 6a, but this applies only to one of three events + +x = { Out.ar(a, SinOsc.ar(500, 0, 0.5)) }.play(target: g, addAction: \addBefore); + + +// also modulate events where fx reads from b + +y = { Out.ar(b, Pulse.ar(700, 0.5, 0.5)) }.play(target: g, addAction: \addBefore); + + +// add a further modulation signal + +z = { Out.ar(a, Formant.ar(700, 1200, mul: 0.5)) }.play(target: g, addAction: \addBefore); + + +// remove two others + +x.free; + +y.free; + + +// stop it also + +z.free; + + +// stop and PbindFx cleanup + +q.stop; + + +// cleanup of other resources, free buses and group + +( +g.free; +a.free; +b.free; +) + + +:: + + +anchor::Ex. 6c:: +subsection::Ex. 6c: Controlling effects with LFOs + +Control the amount / mix of an effect continously. + +Spat SynthDef from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: + +( +// bus for LFO control +c = Bus.control(s, 1); + +// play source with spat and wah-wah effect, +// as initially bus value is zero there is no wah at start + +p = PbindFx([ + \instrument, \source, + \dur, 0.25, + \amp, 0.15, + \midinote, Prand([ + Pwhite(80, 90, 1), + Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf), + ], inf), + \fxOrder, [1, 2], + \decayTime, Pwhite(0.2, 2), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, 2, + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \wah, + // maps each fx synth's mix input to the control bus + \mix, c.asMap, + // other params might still be controlled per event + \cutOffMoveFreq, Pseq([5, 20], inf), + \cleanupDelay, 0.01 + ] +); + +q = p.play; +) + +// chime in with wah from 0 (start phase == -pi/2) + +x = { Out.kr(c, SinOsc.kr(0.15, -pi/2).range(0, 0.8)) }.play + + +// stop and free resources + +( +q.stop; +x.free; +c.free; +) +:: + +anchor::Ex. 7:: +section::Ex. 7: Replacement + +Replacement can affect certain key streams only or whole source resp. fx patterns, the latter can be done with using the option of passing source / fx patterns instead of lists. + +anchor::Ex. 7a:: +subsection::Ex. 7a: Replacement restricted to key streams + +This can be done with Pbind + Pdefn or Pbind + PL, a specific possibility with PbindFx is the replacement of \fxOrder. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +~midi = PLseq([60, 60, 60, 62]); +~fxs = PLseq([0, 0, 1, 3]); + +// Pdefn(\midi, Pseq([60, 60, 60, 62], inf)); +// Pdefn(\fxs, Pseq([0, 0, 1, 3], inf)); + +p = PbindFx([ + \instrument, \source, + \dur, 0.25, + \midinote, PL(\midi), // Pdefn(\midi), + \fxOrder, PL(\fxs), // Pdefn(\fxs), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, 0.15, + + \decayTime, 0.2, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, 2, + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, 0.06, + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \wah, + \cutOffMoveFreq, Pseq([5, 20], inf), + \cleanupDelay, 0.01 + ] +); + +q = p.play; +) + + +// exchange midinote and effect sequencing on the fly + +~midi = PLseq([60, 62, 63]); + +~fxs = PLseq([1, [1, 2], [1, 3], [1, 2, 3]]); + +( +~midi = PLshufn([60, 62, 63]) + + PLshufn([-24, -12, 0]) + + PLshufn([0, [0, 7], [0, 7, 12]]); +) + + +// stop and free resources + +q.stop; + + +:: + + +anchor::Ex. 7b:: +subsection::Ex. 7b: Replacement of source and fx patterns + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// define source and effect patterns + +~midi = PLseq([60, 60, 62, 63]); +~fxs = PLseq([1, [1, 2], [1, 3], [1, 2, 3]]); + +~src = Pbind( + \instrument, \source, + \dur, 0.25, + \midinote, PL(\midi), + \fxOrder, PL(\fxs), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, 0.15, + + \decayTime, 0.2, + \cleanupDelay, Pkey(\decayTime) +); + + +~fx1 = Pbind( + \fx, \spat, + \freq, 2, + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) +); + +~fx2 = Pbind( + \fx, \echo, + \echoDelta, 0.06, + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) +); + +~fx3 = Pbind( + \fx, \wah, + \cutOffMoveFreq, Pseq([5, 20], inf), + \cleanupDelay, 0.01 +); + +// pass PLx or Pdef placeholder patterns to PbindFx +p = PbindFx(PL(\src), PL(\fx1), PL(\fx2), PL(\fx3)); + +q = p.play; +) + + + +( +// chorus fx + +SynthDef(\chorus, { |out, in, amp = 1, loDelay = 0.001, hiDelay = 0.005, + maxDelayTime = 0.1, mix = 1| + var sig, inSig = In.ar(in, 2); + inSig = Mix.fill(10, { |i| + DelayL.ar(inSig, maxDelayTime, LFDNoise3.ar(2).range(loDelay, hiDelay)) + }); + sig = inSig * amp / 2; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; +) + +// replace on the fly, fxOrder sequencing stays the same, but effect changes + +( +~fx3 = Pbind( + \fx, \chorus, + \maxDelayTime, 0.01, + \loDelay, 0.001, + \hiDelay, 0.01, + \cleanupDelay, Pkey(\maxDelayTime) +); +) + +( +// new source SynthDef + +SynthDef(\source_pulse, { |out = 0, freq = 400, decayTime = 0.5, + attackTime = 0.005, amp = 0.1, gate = 1| + var env, sig; + sig = Decay.ar(Impulse.ar(0), decayTime, Pulse.ar(freq)); + env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2); + Out.ar(out, sig ! 2 * env) +}).add; +) + +// replace source, building of phrases with rests + +( +~src = Pbind( + \instrument, \source_pulse, + \dur, Pn(Pshuf([1, 1, 2, 2, 2, 2, 2, 4, Rest(5)], inf)) / 8, + \midinote, PL(\midi) + Pn(Pshuf([-24, -19, 0, 19, 24], inf)), + \fxOrder, PL(\fxs), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, 0.1, + + \decayTime, 0.1, + \cleanupDelay, Pkey(\decayTime) +); +) + +q.stop; +:: + + +anchor::Ex. 7c:: +subsection::Ex. 7c: Replacement with Pbindef + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// source and fxs passed as Pbindefs + +// list of instrument symbols +i = [\src, \fx1, \fx2, \fx3]; + +Pbindef(\src, + \instrument, \source, + \dur, 0.25, + \midinote, Pseq([60, 60, 60, 62], inf), + \fxOrder, Pseq([0, 0, 1, 3], inf), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, 0.15, + + \decayTime, 0.2, + \cleanupDelay, Pkey(\decayTime) +); + +Pbindef(\fx1, + \fx, \spat, + \freq, 2, + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) +); + +Pbindef(\fx2, + \fx, \echo, + \echoDelta, 0.06, + \decayTime, Pwhite(0.3, 1.8), + \cleanupDelay, Pkey(\decayTime) +); + +Pbindef(\fx3, + \fx, \wah, + \cutOffMoveFreq, Pseq([5, 20], inf), + \cleanupDelay, 0.01 +); + + +p = PbindFx(*i.collect { |x| Pbindef(x) }); + +q = p.play; +) + + +// replace some of source's key streams + +( +Pbindef(\src, + \midinote, Pn(Pshuf([60, 62, 63])) + + Pn(Pshuf([-24, -12, 0])) + + Pn(Pshuf([0, [0, 7], [0, 7, 12]])), + \fxOrder, Pseq([[1, 3], [1, 2, 3]], inf) +) +) + +// replace some of an effect's key streams +// note: this kind of multiple key replacement in Pbindef doesn't work with SC 3.5 + +( +Pbindef(\fx3, + \fx, \wah, + [\resLo, \resHi], Pwrand([[200, 300], [1500, 2000]], [0.8, 0.2], inf), + \cutOffMoveFreq, Pseq([1, 5, 20], inf), + \cleanupDelay, 0.01 +) +) + +q.stop; + + +// before playing again do Pbindef cleanup + +i.do { |x| Pbindef(x).clear }; + + +:: + +anchor::Ex. 8:: +section::Ex. 8: GUI control + +Control of fx params with VarGui, control of fx sequencing by code. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// ensure we are in top envir +currentEnvironment = topEnvironment; + +// pattern for fxOrder sequencing +// we want to exchange this on the fly later on + +~fxs = PLshufn([1, 2, 3, [2, 3], [1, 2, 3]]); + +p = PbindFx([ + \instrument, \source, + \dur, PL(\dur), + \degree, PLshufn(\degree), + // Spec returns a float, so write like this + \octave, Pfunc { rrand(~octaveLo.asInteger, ~octaveHi.asInteger) }, + + // we want to read from code in top envir + \fxOrder, PL(\fxs, envir: topEnvironment), + + \lag, Pfunc { |e| e.fxOrder.asArray.includes(2).if { 0 }{ 0.2 } }, + \amp, PL(\amp), + + \attackTime, PLwhite(\attackTimeLo, \attackTimeHi), + \decayTime, PLwhite(\decayTimeLo, \decayTimeHi), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, PLwhite(\spatFreqLo, \spatFreqHi), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \echo, + \echoDelta, PL(\echoDelta), + \decayTime, PLwhite(\echoDecayLo, \echoDecayHi), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \wah, + \resLo, PLwhite(\wahResLo, \wahResHi), + \cutOffMoveFreq, PL(\wahCutOffMoveFreq), + \mix, PL(\wahMix), + \cleanupDelay, 0.01 + ] +); + +v = VarGui([ + \degree, { |i| [0, 6, \lin, 1, i+2] }!4, + \octaveLo, [3, 6, \lin, 1, 4], + \octaveHi, [3, 6, \lin, 1, 6], + \dur, [0.2, 0.3, \lin, 0, 0.2], + \attackTimeLo, [0.01, 0.1, \lin, 0, 0.02], + \attackTimeHi, [0.01, 0.1, \lin, 0, 0.05], + \amp, [0.0, 0.5, \lin, 0, 0.2], + + \decayTimeLo, [0.1, 0.5, \lin, 0, 0.2], + \decayTimeHi, [0.1, 0.5, \lin, 0, 0.4], + + \spatFreqLo, [0.1, 10, \lin, 0, 0.5], + \spatFreqHi, [0.1, 10, \lin, 0, 2], + + \echoDelta, [0.03, 0.1, \lin, 0, 0.05], + \echoDecayLo, [0.1, 2, \lin, 0, 0.3], + \echoDecayHi, [0.1, 2, \lin, 0, 1.8], + + \wahCutOffMoveFreq, [0, 10, \lin, 0, 5], + \wahResLo, [100, 3000, \exp, 0, 200], + \wahResHi, [100, 3000, \exp, 0, 2000], + \wahMix, [0, 1, \lin, 0, 1] + ], stream: p +).gui( + sliderWidth: 350, + labelWidth: 120, + varColorGroups: (0..20).clumps([12, 2, 3, 4]); +); +) + +// start playing with gui and test params +// change of echoDelta necessarily causes a delay as +// delays for events without echo have to be adapted + + +// change effect order sequencing + +~fxs = PLseq([1, 1, 2, 2, 3, 3]); + +// only spat + wah + +~fxs = [1, 3]; + + +// no effects + +~fxs = 0; + + +// kind of polyrhythm with effects and pitches +// all 4 pitch classes are permanently reordered by PLshufn +// fixed effect sequencing + +~fxs = PLseq([1, [1, 2], [1, 2, 3]]); + + +// stop by gui or explicitely + +v.streams[0].stop; +:: + + +anchor::Ex. 9:: +section::Ex. 9: Using value conversions with fx data + +Effects can produce their own characteristic frequencies. For this it can be practical to use Event's value conversion framework. + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// filter bank effect, level of signal very much depends on input frequencies +SynthDef(\klank, { |out, in, freq = 400, add = 7, amp = 1, ringTime = 0.1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = DynKlank.ar(`[freq * [1, add.midiratio], nil, ringTime ! 2], inSig) * amp / 100; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; +) + +( +p = PbindFx([ + \instrument, \source, + \dur, 0.2, + \amp, Pseq([0.15, 0.1, 0.1], inf), + \midinote, Pn(Pshuf([36, 36, 48, 48, 60, 65, 67])) + + Pseq([Pn(0, 40), Pn(7, 10), Pn(-5, 10)], inf) + + Pn(Pshuf([0, 0, 0, [0, 7], [0, 9], [0, 14]])), + \decayTime, Pwhite(0.8, 1.5), + \fxOrder, Pn(Pshuf([1, [1, 2], [1, 2]])), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, Prand([1, 2, 3] / 5, inf), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \klank, + \octave, Pwhite(5, 8), + // passing notes instead of frequencies is more pleasant here + // resulting signal is louder if pitches are near overtones of source + \note, Pn(Pshuf([0, 4, 5, 7])), + \add, Prand([7, 12], inf), + \decayTime, 0.1, + \ringTime, Pwhite(0.1, 0.3), + \mix, 0.7, + \cleanupDelay, Pkey(\ringTime) + ] +); + +q = p.play; +) + +q.stop; + +:: + + +section::Ex. 10: Parallel effects and arbitrary effect graphs + +anchor::Ex. 10a:: +subsection::Ex. 10a: Parallel effects + +Here source is routed to echo #1 and echo #2 in parallel, echo #1 (fx index 2) is a "classical" echo whereas echo #2 (fx index 3), due to short echoDelta, results in an additional frequency. The output of echo #2 is routed to a wah-wah, echo #1 directly to out. + + +image::attachments/PbindFx/PbindFx_graph_4c.png:: + +SynthDefs from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +p = PbindFx([ + \instrument, \source, + \dur, Pseq([Pn(0.2, { rrand(8, 12) }), Pwhite(2.0, 4.0, 1)], inf), + \amp, 0.3, + \midinote, Prand([ + Pwhite(80, 90, 1), + Prand([60, 67, 70, 73]) + Prand([0, -12.3, -23.7], inf), + ], inf), + + \fxOrder, `(0: 1, 1: [2, 3], 3: 4), + // compare with this version, where echo #1 is less present, as it also goes to wah + // \fxOrder, `(0: 1, 1: [2, 3], 3: 4, 2: 4), + + \decayTime, 0.1, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \spat, + \freq, Prand([0.1, 0.8], inf), + \maxDelayTime, 0.001, + \cleanupDelay, 0.1 + ],[ + \fx, \echo, + \echoDelta, 0.1, + \decayTime, 3, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \echo, + \echoDelta, Pwhite(0.01, 0.05), + \decayTime, 5, + \amp, 0.5, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \wah, + \mix, 0.7, + \cutOffMoveFreq, Pseq([1, 2, 5, 10], inf), + \cleanupDelay, 0.05 + ] +); + +q = p.play; +) + +q.stop; +:: + + +anchor::Ex. 10b:: +subsection::Ex. 10b: Modulation graphs + +A generalized modulating effect node has two ins: carrier and modulator. Fx convention of PbindFx demands one single In ugen per fx synth, but two ins can simply be handled by a 2-channel In ugen and hard-panned input signals. + +Spat SynthDef from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + +code:: +( +// sine source +SynthDef(\sine_adsrFixed, { |out = 0, freq = 400, decayTime = 0.5, + att = 0.005, dec = 0.01, sus = 0.2, rel = 0.3, susLevel = 0.5, amp = 0.1| + var env, sig = SinOsc.ar(freq); + env = EnvGen.kr(Env([0, 1, susLevel, susLevel, 0], [att, dec, sus, rel]), doneAction: 2); + Out.ar(out, sig ! 2 * env * amp) +}).add; + +// amplitude modulation synth +SynthDef(\ampMod, { |out, in, dev = 1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = inSig[0] * (inSig[1] * dev + DC.ar(1)) * amp; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +// phase modulation synth +SynthDef(\phaseMod, { |out, in, maxDelay = 0.1, dev = 1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = DelayC.ar(inSig[0], maxDelay, maxDelay * dev * inSig[1], amp); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +// modulator synths, no Ins + +SynthDef(\sineM, { |out, in, freq = 100| + Out.ar(out, [0, SinOsc.ar(freq)]); +}).add; + +SynthDef(\pulseM, { |out, in, freq = 100, width = 0.5| + Out.ar(out, [0, Pulse.ar(freq, width, 2)]); +}).add; + +SynthDef(\sawM, { |out, in, freq = 100| + Out.ar(out, [0, Saw.ar(freq)]); +}).add; +) + +// blend of AM events + +( +p = PbindFx([ + \instrument, \sine_adsrFixed, + \dur, 1, + \susLevel, 1, + \att, 5, + \sus, 0, + \rel, 5, + \amp, 0.03, + \midinote, Pwhite(40, 80), + \fxOrder, `(0: 1, 3: 1, 1: 2), + + \decayTime, 1, + \cleanupDelay, 12 + ],[ + \fx, \ampMod, + \dev, Pwhite(0.1, 0.6) + ],[ + \fx, \spat, + \freq, Pwhite(0.2, 2), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ],[ + \fx, \pulseM, + \freq, Pwhite(200, 1000) + ] +); + +q = p.play; +) + +q.stop; + +:: + +anchor::Ex. 10c:: +subsection::Ex. 10c: Modulation graphs, changed per event + +SynthDefs from Ex. 10b, spat SynthDef from link::#Ex. 1a#Ex.1a::, see also extended server resources defined there. + + +code:: +// fx graphs corresponding to fxOrder `(0:1, 4:1, 1:6) and `(0:1, 5:1, 1:6), src = \sine_adsrFixed: +:: + +image::attachments/PbindFx/PbindFx_graph_4a.png:: + +code:: +// fx graph corresponding to fxOrder `(0:2, 3:2, 2:6), src = \sine_adsrFixed: +:: + +image::attachments/PbindFx/PbindFx_graph_4b.png:: + +code:: + +( +p = PbindFx([ + \instrument, \sine_adsrFixed, + \dur, 0.3, + \susLevel, 1, + \att, 0.01, + \sus, 0.15, + \rel, Pwhite(0.3, 1.2), + \amp, 0.05, + + \midinote, Pwhite(30, 60) + Prand([0, [0, -12.5]], 200), + + // changes between amplitude (pulse and saw) and phase modulation (sine) + + \fxOrder, Pn(Pshuf([ + `(0:1, 4:1, 1:6), + `(0:1, 5:1, 1:6), + `(0:2, 3:2, 2:6) + ])), + + // equivalent: + // the source stream returns pairs, where the first number indicates + // the modulation type and the second number the modulator, + // the collect function packs the data into the right format of a ref'd Event. + + // \fxOrder, Pn(Pshuf([ [1, 4], [1, 5], [2, 3] ])) + // .collect { |x| ().putPairs([0, x[0], x[1], x[0], x[0], 6]).asRef }, + + \decayTime, 2, + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \ampMod, + \dev, Pwhite(0.1, 0.5) + ],[ + \fx, \phaseMod, + \dev, Pwhite(0.03, 0.05) + ],[ + \fx, \sineM, + \freq, Pwhite(150, 700) + ],[ + \fx, \sawM, + \freq, Pwhite(150, 700) + ],[ + \fx, \pulseM, + \freq, Pwhite(150, 700) + ],[ + \fx, \spat, + \freq, Pwhite(0.1, 1), + \maxDelayTime, 0.005, + \cleanupDelay, Pkey(\maxDelayTime) + ] +); + +q = p.play; +) + +q.stop; + +:: + + + diff --git a/HelpSource/Classes/PlaceAll.schelp b/HelpSource/Classes/PlaceAll.schelp new file mode 100644 index 0000000..c518284 --- /dev/null +++ b/HelpSource/Classes/PlaceAll.schelp @@ -0,0 +1,85 @@ +CLASS::PlaceAll +summary::Arbitrarily nested embedding of subarrays +categories::Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Classes/Place, Classes/Ppatlace + + +DESCRIPTION:: + + +PlaceAll is integrating Ppatlace and Place (taking items as well as Patterns) and allows an arbitrary depth of nesting arrays. + + +CLASSMETHODS:: + +method::new + +Creates a new PlaceAll object. + +argument::list +Array which may contain subarrays. Leaves of the array tree may be Patterns, Streams or other Items to be embedded. + +argument::repeats +Number of list loops. Defaults to 1. + +argument::offset +List index offset. Defaults to 0. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +p = Pbind( + \midinote, PlaceAll([[60, 61], 70, [80, [81, 81.5], 82]], inf), + \dur, 0.2 +); + +x = p.play; +) + +x.stop; + + +// to distinguish subarrays from arrays to be taken as output use Refs, +// as wrapping in another array wouldn't do + +( +p = Pbind( + \midinote, PlaceAll([[60, 61], 70, [80, `[81, 81.5], 82]], inf), + \dur, 0.2 +); + +x = p.play; +) + + +x.stop; + + +// Items may also be Patterns or Streams + +( +p = Pbind( + \midinote, PlaceAll([[60, 61], 70, [80, Pwhite(84.0, 89), 82]], inf), + \dur, 0.2 +); + +x = p.play; +) + + +x.stop; + + + +:: + + \ No newline at end of file diff --git a/HelpSource/Classes/Platform.ext.schelp b/HelpSource/Classes/Platform.ext.schelp new file mode 100755 index 0000000..a7d773f --- /dev/null +++ b/HelpSource/Classes/Platform.ext.schelp @@ -0,0 +1,12 @@ + +CLASSMETHODS:: + +method:: miSCellaneousDirs + +Returns an Array of Strings, representing found directories of miSCellaneous lib. The method is searching at places of the most likely installation scenarios: +user and system extension as well as quark extension directories. + +argument::withWarnings +Determines if warnings should be posted in case of no or more than one matches. + + diff --git a/HelpSource/Classes/PmonoPar.schelp b/HelpSource/Classes/PmonoPar.schelp new file mode 100644 index 0000000..84973ec --- /dev/null +++ b/HelpSource/Classes/PmonoPar.schelp @@ -0,0 +1,156 @@ +CLASS:: PmonoPar +summary:: monophonic event pattern for an arbitrary number of timed setting streams +categories::Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Pmono, Classes/PpolyPar, Classes/PbindFx + + +DESCRIPTION:: + +This is similar to Pmono, but allows an arbitrary number of differently timed setting streams in parallel. + +strong::History::: PmonoPar and PpolyPar grew out of discussions on sc-users list, based on an example by Jonatan Liljedahl. Thanks to him, Ron Kuivila, user Monsieur and others for their comments on this – I then suggested classes PsetGroup and PsetFxGroup, which internally used Pgroup. Meanwhile I reworked the implementation, but it's still based on groups. I renamed PsetGroup to PmonoPar – as this makes the functionality more clear – and PsetFxGroup to PpolyPar, as it can be used with or without effect synths, the crucial point is the setting of parallel streams. + +CLASSMETHODS:: + +method::new + +Creates a new PmonoPar object. + +argument::setPatternPairs +SequenceableCollection of SequenceableCollections containing key/value pairs. +Each of the inner collections represents the data of one synth setting stream. +Per convention key/value pairs written after a pair with \dur will cause setting, pairs before will not. +If keys \midinote, \note or \degree are occuring after \dur, they will be converted to a frequency value, +which will be used for setting the arg 'freq'. + +argument::defname +Symbol or String. Name of the SynthDef to be used for the synth being set. +Defaults to \default. + +argument::offset +Number. Offset to be taken for time-shifting synth init and streams. Defaults to 1e-6. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +anchor::Ex.1a:: +subsection::Ex.1a: PmonoPar with differently timed streams + +code:: + +// per convention keys after \dur are the ones to be set +// playing ends after end of last stream + +( +p = PmonoPar([ + [ + \dur, 1.0, + \pan, Pser([-0.9, 0, 0.9], 8) + ],[ + \dur, 0.4, + \freq, Pexprand(300, 1000, 24) + ],[ + \dur, 0.2, + \amp, Pseq([0.05, 0.3], 30) + ] +]).trace.play; +) +:: + + +anchor::Ex.1b:: +subsection::Ex.1b: Passing values by using the value conversion framework + + +code:: + +// if \degree, \note or \midinote are occuring after \dur, +// a frequency value will be calculated according to Event's usual conversion framework +// and used for setting the arg 'freq'. + +( +p = PmonoPar([ + [ + \dur, 1.0, + \pan, Pser([-0.9, 0, 0.9], 8) + ],[ + \dur, 0.4, + \midinote, Pseq((70..75), 7) + ],[ + \dur, 0.2, + \amp, Pseq([0.05, 0.3], 30) + ] +]).trace.play; +) + +:: + + +anchor::Ex.2:: +subsection::Ex.2: Data sharing between streams of PmonoPar + +code:: + +// define two Pbinds of same length, play first + +// data sharing with rhythms of coinciding entry points is sure as streams are time-shifted + +( +p = PmonoPar([ + [ + \dur, Prand([1, 1, 2]/3, inf).collect(~dur = _).trace, // or: .collect { |x| ~dur = x } .trace + \amp, Pseq([0.2, 0.05], 15).trace + ],[ + \dur, Pfunc { ~dur / 2 }, + \midinote, Pshuf((60..85)) + ] +]).trace.play; +) + +:: + + +anchor::Ex.3:: +subsection::Ex.3: Data sharing between streams of parallel PmonoPars + +code:: + +// data sharing between streams of same PmonoPar and streams of second PmonoPar, +// use of Ptpar ensures that first stream of second PmonoPar comes after first stream of first PmonoPar, +// consider also PpolyPar for such type of usage + +( +p = PmonoPar([ + [ + \dur, Prand([1, 1, 2]/3, 40).collect(~dur = _), + \amp, Pseq([0.3, 0.1], 15) + ],[ + \dur, Pfunc { ~dur / 2 }, + \midinote, Pshuf((50..70)) + ] +]); + +q = PmonoPar([ + [ + \dur, Pfunc { ~dur }, + \amp, Pseq([0.3, 0.1], 15) + ],[ + \dur, Pfunc { ~dur / 3 }, + \midinote, Pshuf((75..95), 2) + ] +]); + +r = Ptpar([0, p, 1e-5, q]).trace.play +) +:: + + diff --git a/HelpSource/Classes/PpolyPar.schelp b/HelpSource/Classes/PpolyPar.schelp new file mode 100644 index 0000000..8ec525e --- /dev/null +++ b/HelpSource/Classes/PpolyPar.schelp @@ -0,0 +1,500 @@ +CLASS:: PpolyPar +summary:: polyphonic event pattern for an arbitrary number of timed setting streams +categories::Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Pmono, Classes/PmonoPar, Classes/PbindFx + + +DESCRIPTION:: + +This is similar to PmonoPar and allows an arbitrary number of monophonic streams as well as an arbitrary number of differently timed setting streams applied to them in parallel. Each setting action can affect an arbitrary combination of running synths. PpolyPar can be used for polyphonic sources alone as well as in combination with effects. + +strong::History::: PmonoPar and PpolyPar grew out of discussions on sc-users list, based on an example by Jonatan Liljedahl. Thanks to him, Ron Kuivila, user Monsieur and others for their comments on this – I then suggested classes PsetGroup and PsetFxGroup, which internally used Pgroup. Meanwhile I reworked the implementation, but it's still based on groups. I renamed PsetGroup to PmonoPar – as this makes the functionality more clear – and PsetFxGroup to PpolyPar, as it can be used with or without effect synths, the crucial point is the setting of parallel streams. + +CLASSMETHODS:: + +method::new + +Creates a new PpolyPar object. + +argument::setPatternPairs +SequenceableCollection of SequenceableCollections containing key/value pairs. +Each of the inner collections represents the data of one synth setting stream. +Per convention key/value pairs written after a pair with \dur will cause setting, pairs before will not. +If keys \midinote, \note or \degree are occuring after \dur, they will be converted to a frequency value, which will be used for setting the arg 'freq'. + +Also per convention, if the number of setting streams (the size of strong::setPatternPairs::) equals the number +of synths (the size of strong::defNames::), the settings of stream i will automatically affect synth i. +If sizes are unequal, each collection of key/value pairs needs a pair with key strong::\synths:: and a value. +This value can be an Integer, meaning synth i, or a SequenceableCollection of Integers, in which case all of those +synths will be affected by the setting. The value can also be a Pattern, so that synths to be set +might change from event to event (see examples). + +argument::defNames +SequenceableCollection of Symbols or Strings. Names of the SynthDefs to be used for the synths being set. +Defaults to #[\default]. + +argument::order +SequenceableCollection of Integers indicating the order of nodes passed to strong::defNames::. +Defaults to nil, in that case an order 0, ... , (defNames.size - 1) is assumed, i.e. synth i comes before synth i+1. + +argument::offset +Number. Offset to be taken for time-shifting synth inits and streams. Defaults to 1e-6. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +anchor::Ex.1a:: +subsection::Ex.1a: PpolyPar with different instruments + +code:: + +// basic SynthDefs, EnvGate invents a gate arg which is necessary for release + +( +SynthDef(\saw, { |freq = 400, freqlag = 0.0, amp = 0.1, amplag = 0.01| + Out.ar(0, Saw.ar(Lag.kr(freq, freqlag), VarLag.kr(amp, amplag, warp: 1)) ! 2 * EnvGate()); +}).add; + +SynthDef(\pulse, { |freq = 400, freqlag = 0.0, amp = 0.1, amplag = 0.05| + Out.ar(0, Pulse.ar(Lag.kr(freq, freqlag), mul: VarLag.kr(amp, amplag, warp: 1)) ! 2 * EnvGate()); +}).add; + +SynthDef(\sine, { |freq = 400, freqlag = 0.0, amp = 0.1, amplag = 0.05| + Out.ar(0, SinOsc.ar(Lag.kr(freq, freqlag), 0, mul: VarLag.kr(amp, amplag, warp: 1)) ! 2 * EnvGate()); +}).add; +) + +// simple usage, each stream is setting the corresponding instrument + +// per convention keys after \dur are the ones to be set +// note that you'd need \freq (the SynthDef arg) + +( +p = PpolyPar([[ + \dur, 1/6, + \amp, Pwrand([0, 0.07], [1, 7]/8, inf), + \midinote, Pshuf((30..68), inf) + ],[ + \dur, Prand([1, 1, 2]/4, inf), + \amp, Pwrand([0, 0.07, 0.1], [0.3, 0.3, 0.4], inf), + \freqlag, 0.2, + \amplag, Prand([0.2, 0.4], inf), + \midinote, Pbrown(70, 90, 5) + ]], + [\saw, \pulse] +).play; +) + +p.stop; +:: + + +anchor::Ex.1b:: +subsection::Ex.1b: PpolyPar with different instruments and overlapping settings + + +code:: + +// SynthDefs from Ex. 1a + +( +// Function to create midinote patterns in different ranges + +r = { |add = 0| Pstutter(5, Pwhite(60, 70) + add) }; + +// each setting stream affects two synths: those of corresponding indices of \synths, +// but only with one value: the Integer polled from the Pstutter stream + +p = PpolyPar([[ + \synths, [0, 1], + \dur, 1/6, + \midinote, r.(), + \amp, 0.04 + ],[ + \synths, [0, 2], + \dur, 1/4, + \midinote, r.(10), + \amp, 0.03 + ],[ + \synths, [1, 2], + \dur, 1/3, + \midinote, r.(20), + \amp, 0.05 + ]], + [\saw, \pulse, \sine] +).play +) + +p.stop; +:: + + +anchor::Ex.1c:: +subsection::Ex.1c: PpolyPar with different instruments, overlapping settings with array dispatch + + +code:: + +// SynthDefs from Ex. 1a + +( +// Similar to Ex. 1b, but the midinote pattern will cause the stream to generate arrays of two elements, +// they will be distributed to the indicated synths + +r = { |add = 0, int = 7| Pstutter(5, Pwhite(60, 65) + [0, int] + add) }; + +// each setting streams affects two synths: those of corresponding indices of \synths + +p = PpolyPar([[ + \synths, [0, 1], + \dur, 1/6, + \midinote, r.(0, 5), + \amp, 0.04 + ],[ + \synths, [0, 2], + \dur, 1/4, + \midinote, r.(10, 6), + \amp, 0.03 + ],[ + \synths, [1, 2], + \dur, 1/3, + \midinote, r.(20, 7), + \amp, 0.05 + ]], + [\saw, \pulse, \sine] +).play +) + +p.stop; + +:: + + +anchor::Ex.2a:: +subsection::Ex.2a: PpolyPar with one effect synth + +code:: + +( +// With t_gate a percussive envelope will be triggered, +// so articulation can be achieved within a monophonic stream. +// This is similar to Pbind, though only if envelopes are shorter than entry time differences. + +SynthDef(\test, { |out = 0, freq = 440, att = 0.01, rel = 0.1, amp = 0.1, t_gate = 1| + var sig = Saw.ar(freq, amp), delayedSig; + sig = sig!2 * EnvGen.ar(Env.perc(att, rel), t_gate); + // add some spatial variance by LFO on delaytime + delayedSig = DelayL.ar(sig, delaytime: { LFDNoise3.kr(0.5).range(0.005, 0.02) } ! 2); + Out.ar(out, delayedSig * EnvGate()) +}).add; + +// Effect synthdefs with in and out bus, +// both get an EnvGate which introduces a gate arg for proper release, +// one could also add a gate arg and an EnvGen using it. + +// wet/dry-relation is fixed, considering the example with fx chain a bypass arg is introduced + +SynthDef(\echo, { |out = 0, in, maxdtime = 0.2, dtime = 0.2, decay = 3, amp = 0.5, bypass = 0| + var sig, insig; + insig = In.ar(in, 2); + sig = CombL.ar(insig, maxdtime, dtime, decay, amp, add: insig) * EnvGate(); + Out.ar(out, bypass * insig + ((1 - bypass) * sig)); +}).add; + + +SynthDef(\wah, { |out = 0, in, freqLo = 200, freqHi = 5000, modFreq = 10, amp = 0.7, bypass = 0| + var sig, insig; + insig = In.ar(in, 2); + sig = RLPF.ar( + insig, + LinExp.kr(LFDNoise1.kr(modFreq), -1, 1, freqLo, freqHi), + 0.1, + amp, + insig * 0.3 + ).softclip * 0.8 * EnvGate(); + Out.ar(out, bypass * insig + ((1 - bypass) * sig)); +}).add; +) + + +// Whereas node order is done by PpolyPar, bus handling is the user's responsibility, +// it looks more flexible to me to define buses separately. + +// one fx + +b = Bus.audio(s, 2); + +( +p = PpolyPar([[ + \dur, 0.5, + \amp, 0.2, + \out, b, + \t_gate, 1, + \midinote, Pwhite(50, 100) + ],[ + // dur = inf causes just a running fx synth, none of its args is set by a stream + \dur, inf, + \in, b, + \dtime, 0.1, + \decay, 3 + ]], + [\test, \echo] +).play +) + +p.stop; + +b.free; + +:: + + +anchor::Ex.2b:: +subsection::Ex.2b: PpolyPar with more effect synths + +code:: + +// SynthDefs from Ex. 2a + +( +b = Bus.audio(s, 2); +c = Bus.audio(s, 2); +) + + +// still none of the effects is set by a stream + +( +p = PpolyPar([[ + // values before \dur are not sent to server, so do this work here: + // echo (out b) is coupled with short release time + // wah (out c) is coupled with longer release time + \data, Prand([[b, 0.1], [c, 0.5]], inf), + \dur, Prand([1, 1, 2]/5, inf), + \amp, 0.3, + // data dispatch from above, these values will be sent + \rel, Pkey(\data).collect(_[1]), + \out, Pkey(\data).collect(_[0]), + \t_gate, 1, + \midinote, Pwhite(50, 100) + ],[ + \dur, inf, + \in, b, + \out, 0, + \dtime, 0.1, + \decay, 3 + ],[ + \dur, inf, + \in, c, + \amp, 0.3 + ]], + [\test, \echo, \wah] +).play; +) + +p.stop; + +( +b.free; +c.free; +) + + +:: + + + +anchor::Ex.2c:: +subsection::Ex.2c: PpolyPar with more effect synths and streamed setting + +code:: + +// SynthDefs from Ex. 2a + +( +b = Bus.audio(s, 2); +c = Bus.audio(s, 2); +) + + +// effects set by streams + +( +p = PpolyPar([[ + // values before \dur are not sent to server, so do this work here: + // echo (out b) is coupled with short release time + // wah (out c) is coupled with longer release time + \data, Prand([[b, 0.1], [c, 0.5]], inf), + // will get "bars" of length 4/5 + \dur, Pn(Pshuf([1, 1, 2]/5)), + \amp, 0.3, + // data dispatch from above, these values will be sent + \rel, Pkey(\data).collect(_[1]), + \out, Pkey(\data).collect(_[0]), + \t_gate, 1, + \midinote, Pwhite(50, 100) + ],[ + \dur, 4/5, + \in, b, + // change delaytime per "bar", random add avoids repeating echo frequencies + \dtime, Pshuf([1, 2, 4]/40, inf) + (Pwhite(-0.5, 0.5)/40), + \decay, 3 + ],[ + \dur, 4/5, + \in, c, + // change modFreq per "bar" + \modFreq, Pshuf((1..20), inf), + \amp, 0.3 + ]], + [\test, \echo, \wah] +).play +) + +p.stop; + +( +b.free; +c.free; +) + +:: + + +anchor::Ex.2d:: +subsection::Ex.2d: PpolyPar with more effect synths, streamed setting and more than one setting stream per synth + +code:: + +// SynthDefs from Ex. 2a + +( +b = Bus.audio(s, 2); +c = Bus.audio(s, 2); +) + + +// Now we have more setting streams than synths, +// so we need to define which synth is to be set by which stream, +// this done via the \synths key, which must be contained in every collection of pairs. + +( +p = PpolyPar([[ + \synths, 0, + // values before \dur are not sent to server, so do this work here: + // echo (out b) is coupled with short release time + // wah (out c) is coupled with longer release time + \data, Prand([[b, 0.1], [c, 0.5]], inf), + // will get "bars" of length 4/5 + \dur, Pn(Pshuf([1, 1, 2]/5)), + \amp, 0.3, + // data dispatch from above, these values will be sent + \rel, Pkey(\data).collect(_[1]), + \out, Pkey(\data).collect(_[0]), + \t_gate, 1 + ],[ + // stream setting frequency + \synths, 0, + \dur, 1/20, + \midinote, Pshuf((45..90), inf) + ],[ + \synths, 1, + \dur, 4/5, + \in, b, + // change delaytime per "bar", random add avoids repeating echo frequencies + \dtime, Pshuf([1, 2, 4]/40, inf) + (Pwhite(-0.5, 0.5)/40), + \decay, 3 + ],[ + \synths, 2, + \dur, 4/5, + \in, c, + // change modFreq per "bar" + \modFreq, Pshuf((1..20), inf), + \amp, 0.3 + ]], + [\test, \echo, \wah] +).play +) + +p.stop; + +( +b.free; +c.free; +) + +:: + + +anchor::Ex.2e:: +subsection::Ex.2e: PpolyPar with effect chain and streamed fx repatching + +code:: +// SynthDefs from Ex. 2a + +( +b = Bus.audio(s, 2); +c = Bus.audio(s, 2); +) + +// Here effects are chained in order - see buses passed to \in and \out +// Again more setting streams than synths, so the \synths key is needed. + +( +p = PpolyPar([[ + \synths, 0, // source synth + // will get "bars" of length 4/5 + \dur, Pn(Pshuf([1, 1, 2]/5)), + \amp, 0.3, + \rel, 0.2, + \out, b, + \t_gate, 1 + ],[ + // freq rhythm might differ from envelope rhythm (stream 0) + \synths, 0, + \dur, Pn(Pshuf([1, 1, 2]/5)), + \midinote, Pshuf((45..90), inf) + ],[ + \synths, 1, // echo + \dur, 4/5, + \in, b, // gets from source and sends to wah + \out, c, + // change delaytime per "bar", random add avoids repeating echo frequencies + \dtime, Pshuf([1, 2, 4]/20, inf) + (Pwhite(-0.5, 0.5)/20), + \decay, 3 + ],[ + \synths, 2, // wah + \dur, 4/5, + \in, c, // gets from echo, sends to out 0 by default + // change modFreq per "bar" + \modFreq, Pshuf((1..20), inf), + \amp, 0.3 + ],[ + // this stream determines effects in action by setting bypass args of both fx synths + \synths, [1, 2], + \dur, 1/5, + // alternate bypassing of wah synth + \bypass, Pseq([[0, 0], [0, 1]], inf) + ]], + [\test, \echo, \wah] +).play +) + +p.stop; + +( +b.free; +c.free; +) + + +:: + diff --git a/HelpSource/Classes/Pshufn.schelp b/HelpSource/Classes/Pshufn.schelp new file mode 100644 index 0000000..cbb92f1 --- /dev/null +++ b/HelpSource/Classes/Pshufn.schelp @@ -0,0 +1,51 @@ +CLASS::Pshufn +summary::Pshuf with continuing permutations +categories::Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Classes/Pshuf + + +DESCRIPTION:: + + +Variation of Pshuf which scrambles the list with every repeat. + + + +CLASSMETHODS:: + +method::new + +Creates a new Pshufn object. + +argument::list +List to be scrambled. + +argument::repeats +Number of permutations. Defaults to 1. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +p = Pbind( + \midinote, Pshufn((70..73), inf), + \dur, 0.2 +); +) + +x = p.play; + +x.stop; + +:: + + \ No newline at end of file diff --git a/HelpSource/Classes/Psieve.schelp b/HelpSource/Classes/Psieve.schelp new file mode 100644 index 0000000..ae98b7e --- /dev/null +++ b/HelpSource/Classes/Psieve.schelp @@ -0,0 +1,19 @@ + +CLASS::Psieve +summary::Abstract superclass of sieve patterns +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Sieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +PSVx sieve patterns inherit from Psieve. Normally you don't have to use Psieve directly. For an introduction and examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + +CLASSMETHODS:: + + +private:: miSC_checkGenList, miSC_checkOffsetGenList + +method::limit + +Getter and setter for Integer limit of all Psieve patterns. You might want to set it globally when working with large numbers. Default to 65536. \ No newline at end of file diff --git a/HelpSource/Classes/PsymNilSafe.schelp b/HelpSource/Classes/PsymNilSafe.schelp new file mode 100644 index 0000000..595fc5d --- /dev/null +++ b/HelpSource/Classes/PsymNilSafe.schelp @@ -0,0 +1,55 @@ +CLASS::PsymNilSafe +summary::Psym variant that avoids hangs if all referenced patterns return nil +categories:: Libraries>miSCellaneous>Other patterns +related:: Overviews/miSCellaneous, Classes/Psym, Tutorials/PLx_and_live_coding_with_Strings + + +DESCRIPTION:: +This adapts an idea of James Harkins' PnNilSafe (ddwPatterns quark) for Psym. If all patterns in the Dictinonary return nil, then Psym's embedInStream can produce an infinite loop, as it never yields. PnNilSafe can't be wrapped around Psym, but the check with logical time can be built into Psym itself. The wrapping into PsymNilSafe can shortly be written by applying link::Classes/Pattern#-symplay:: instead of link::Classes/Pattern#-play::. See link::Tutorials/PLx_and_live_coding_with_Strings:: for more examples. + +CLASSMETHODS:: + +method::new + +Creates a new PsymNilSafe object. strong::pattern:: expects a pattern of Symbols, strong::dict:: the lookup dictionary and strong::defaults:: to the current Environment. strong::maxNull:: is the number of events with delta = 0 after which PsymNilSafe's method 'embedInStream' yields and thus stops a potentially endless loop. strong::maxNull:: defaults to 128. + + +INSTANCEMETHODS:: + +method::maxNull + +Getter and setter for PsymNilSafe's variable maxNull. + + + + +SECTION::Example + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +x = Pbind(\midinote, Pseries(60, 1, 10), \dur, 0.5).asStream; +y = Pbind(\midinote, Pseries(90, -1, 10), \dur, 0.5).asStream; + +z = Pseq([2, 3, 1, 2], 1).asStream; + +~a = Pfuncn({ x.next(()) }, { z.next }); +~b = Pfuncn({ y.next(()) }, { z.next }); + +PsymNilSafe(Pseq("ab", inf)).trace.play; + +// shorter with method 'symplay': +// trace indicates all events with delta = 0 (maxNull = 128) in the post window +// Pseq("ab", inf).trace.symplay + + +// ATTENTION: with Psym the example leads to a SC hang ! +// Psym(Pseq("ab", inf), currentEnvironment).trace.play +) +:: + diff --git a/HelpSource/Classes/SequenceableCollection.ext.schelp b/HelpSource/Classes/SequenceableCollection.ext.schelp new file mode 100755 index 0000000..3e91b61 --- /dev/null +++ b/HelpSource/Classes/SequenceableCollection.ext.schelp @@ -0,0 +1,195 @@ + +INSTANCEMETHODS:: + + +private:: miSC_isGrouping, miSC_isConnected, miSC_groupingFromIndices, miSC_isKeysAndValues, miSC_isPossiblePbindData +private:: miSC_isPossiblePbindArgs, miSC_hasNoReservedKeys, miSC_hasNoReservedKeysInPbindData +private:: miSC_hasNoReservedKeysInPbindArgs, miSC_isPossibleHelpSynthArgs, miSC_isPossibleHelpSynthParArgs, miSC_areControlRateSynthDefs +private:: miSC_isIndexSubset + +private:: miSC_isGrouping, miSC_isConnected, miSC_groupingFromIndices + +private:: miSC_pfuncPbindsFromTuples, miSC_specAsArray, miSC_oddSpecAsArray, miSC_sVarGuiData, miSC_pVarGuiData + +private:: miSC_makeLacePat, miSC_makeLaceList + +private:: miSC_partitionIndex + +private:: miSC_getClutch, miSC_atKey, miSC_makeStartFxBundle, miSC_makeStartZeroBundle, miSC_checkFxOrder, miSC_fxOrderWarnString, miSC_getTopoOrder, miSC_getPredecessors, miSC_getSuccessors, miSC_getFxOrders, miSC_getFxBusData, miSC_collectEvalWithoutKeyPairs + + +private:: miSC_lowestIndexForWhichGreaterEqual, miSC_highestIndexForWhichLessEqual, miSC_checkSymmetricPeriods, miSC_checkCharacteristicPeriod, miSC_streamifySieveItems, miSC_streamifySieveItems, miSC_isQuasiSymmetricRange, miSC_isSymmetricRange, miSC_smallestPeriodLength, miSC_symmetryType + +private:: miSC_getFFTbufSizes + +private:: miSC_unifySize + +private:: miSC_Dmultiply + +private:: miSC_Dmultiply2 + + +method:: specPairsDup +Duplicates pairs strong::num:: times. See link::Classes/VarGui#Ex. 5a#Ex.5a:: + +method:: specPairsDupGroups +Returns an index grouping for rearranging a collection that has been duplicated strong::num:: times. See link::Classes/VarGui#Ex. 5a#Ex.5a:: + + + +method:: sVarGui +See link::Tutorials/VarGui_shortcut_builds::. Instantiate a VarGui object for control of Synths derived from a collection of SynthDef names (Symbols / Strings). Options for Synth controls are taken from the corresponding arg Dictionaries. Size of receiver must equal strong::N::, the number of Dictionaries. + +argument::... args +arg Dictionaries, see link::Classes/Symbol#-sVarGui:: for valid arg syntax, with exception of server. Optionally the last item of args may be a Server to send node messages for synth control. Defaults to the default server. + + + + + +method:: pVarGui +See link::Tutorials/VarGui_shortcut_builds::. Instantiate a VarGui object for control of Pbinds / EventStreamPlayers derived from a collection of SynthDef names (Symbols / Strings). Options for controls are taken from the corresponding arg Dictionaries. Size of collection must equal strong::N::, the number of Dictionaries. + +argument::... args +arg Dictionaries, see link::Classes/Symbol#-pVarGui:: for valid arg syntax. + + + + + + +method:: spVarGui +See link::Tutorials/VarGui_shortcut_builds::. Instantiate a VarGui object for control of Pbinds / EventStreamPlayers and Synths derived from SynthDef names (Symbols / Strings). Thus receiver must be of the form strong::[ synthNames, pbindSynthNames ]::, whereby strong::synthNames:: and strong::pbindSynthNames:: may be Symbols / Strings or SequenceableCollections of Symbols / Strings. + +argument::sVarGuiArgDictionaries +arg Dictionary or SequenceableCollection thereof, whose size must be equal to that of strong::synthNames:: (if a collection). See link::Classes/Symbol#-sVarGui:: for valid arg syntax. Defaults to []. + +argument::pVarGuiArgDictionaries +arg Dictionary or SequenceableCollection thereof, whose size must be equal to that of strong::pbindSynthNames:: (if a collection). See link::Classes/Symbol#-pVarGui:: for valid arg syntax. Defaults to []. + +argument::server +Server. The server to send node messages for synth control. Defaults to the default server. + + + + +method:: psVarGui +See link::Tutorials/VarGui_shortcut_builds::. Instantiate a VarGui object for control of Pbinds / EventStreamPlayers and Synths derived from SynthDef names (Symbols / Strings). Thus receiver must be of the form strong::[ pbindSynthNames, synthNames ]::, whereby strong::pbindSynthNames:: and strong::synthNames:: may be Symbols / Strings or SequenceableCollections of Symbols / Strings. + +argument::pVarGuiArgDictionaries +arg Dictionary or SequenceableCollection thereof, whose size must be equal to that of strong::pbindSynthNames:: (if a collection). See link::Classes/Symbol#-pVarGui:: for valid arg syntax. Defaults to []. + +argument::sVarGuiArgDictionaries +arg Dictionary or SequenceableCollection thereof, whose size must be equal to that of strong::synthNames:: (if a collection). See link::Classes/Symbol#-sVarGui:: for valid arg syntax. Defaults to []. + +argument::server +Server. The server to send node messages for synth control. Defaults to the default server. + + + + + +method::ev +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives an Event from an array of key/value-pairs. Values might be functions that refer to prior keys of the array. + +method::on +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives an Event from an array with method link::Classes/SequenceableCollection#-ev:: and plays it using link::Classes/Event#-on::. + +method::pa +See link::Tutorials/Other_event_and_pattern_shortcuts::. Expects basically an array of key/value-pairs ready for an event pattern. Exception: values might be functions that refer to prior keys of the array, thus delivering an shortcut functionality of the common Pfunc { |e| ... } construct (and similar to Pkey). + +method::p +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a Pbind from an array involving link::Classes/SequenceableCollection#-pa::. + + +method::pm +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a Pmono with instrument passed as Symbol from an array involving link::Classes/SequenceableCollection#-pa::. + +argument::sym +Symbol. + + +method::pma +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a PmonoArtic with instrument passed as Symbol from an array involving link::Classes/SequenceableCollection#-pa::. + +argument::sym +Symbol. + + +method::pbf +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a Pbindef with reference passed as Symbol from an array involving link::Classes/SequenceableCollection#-pa::. + +argument::sym +Symbol. + + + +method::pp +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a Pbind from an array involving link::Classes/SequenceableCollection#-pa::. Arguments strong::clock::, strong::protoEvent:: and strong::quant:: are used by method link::Classes/Pattern#-play::. + +method::ppm +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a Pmono with instrument strong::sym:: (a Symbol) from an array involving link::Classes/SequenceableCollection#-pa::. Arguments strong::clock::, strong::protoEvent:: and strong::quant:: are used by method link::Classes/Pattern#-play::. + +method::ppma +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a PmonoArtic with instrument strong::sym:: (a Symbol) from an array involving link::Classes/SequenceableCollection#-pa::. Arguments strong::clock::, strong::protoEvent:: and strong::quant:: are used by method link::Classes/Pattern#-play::. + + +method::ppma +See link::Tutorials/Other_event_and_pattern_shortcuts::. Derives a Pbindef with reference strong::sym:: (a Symbol) from an array involving link::Classes/SequenceableCollection#-pa::. Arguments strong::clock::, strong::protoEvent:: and strong::quant:: are used by method link::Classes/Pattern#-play::. + + + +method::eventShortcuts + +Applies method to all items of the collection. See also link::Classes/EventShortcuts::, link::Classes/Pattern#-eventShortcuts::, link::Classes/Event#-eventShortcuts:: and link::Tutorials/PLx_and_live_coding_with_Strings:: + + + + +method:: toSieve + +Expects a strictly ascending collection of Integers and converts to a new Sieve. +See link::Tutorials/Sieves_and_Psieve_patterns:: + +argument::fromMode +Determines how to interpret the receiver. Must be Symbol 'points' (or 'p'), or Symbol 'intervals' (or 'i'). +Defaults to 'points'. + +argument::toMode +Determines resulting mode. Must be Symbol 'points' (or 'p'), or Symbol 'intervals' (or 'i'). +Defaults to 'points'. + +argument::addOffset +Integer offset added to the result. Defaults to 0. + +argument::withCheck +Boolean. Determines if receiver should be checked. Defaults to true. +In normal use it's recommended not to change this, as Sieve methods +assume properly ordered lists. It only makes sense in a case where +large collection data, that is known to be ordered, has to be converted. + + + +method:: lcmByGcd + +Expects a SequenceableCollection of Integers and calculates the least common multiple by using the greatest common divisor. +This can avoid problems with large numbers. See link::Tutorials/Sieves_and_Psieve_patterns#4b:: + + +method:: lcmByFactors + +Expects a SequenceableCollection of Integers and calculates the least common multiple by prime factors. +This can avoid problems with large numbers. Returns an array with lcm as first item, an array with prime factors of +lcm as second item and an array of receiver's and all arguments' prime factors. +See link::Tutorials/Sieves_and_Psieve_patterns#4b:: + + +method:: adjustZeroXs +Sets all zero crossing positions of (sound) Buffers in a SequenceableCollection to 0. In most cases this ensures smoother waveforms when using ZeroXBufRd / TZeroXBufRd. See link::Classes/ZeroXBufRd#Éx. 7:: and link::Classes/ZeroXBufWr#Éx. 2::, it works in analogy to ZeroXBufWr's flag adjustZeroXs set to 1. Asynchronous. + +argument::zeroXBuf +SequenceableColletion of Buffers of zero crossings, analysed with ZeroXBufWr. + +argument::action +Action function or SequenceableCollection of such to be performed after the setting messages have been sent. Gets array of zero crossings as argument. + diff --git a/HelpSource/Classes/Set.ext.schelp b/HelpSource/Classes/Set.ext.schelp new file mode 100755 index 0000000..bad73e7 --- /dev/null +++ b/HelpSource/Classes/Set.ext.schelp @@ -0,0 +1,5 @@ + +INSTANCEMETHODS:: + + +private::miSC_copy diff --git a/HelpSource/Classes/Sieve.schelp b/HelpSource/Classes/Sieve.schelp new file mode 100644 index 0000000..bf64909 --- /dev/null +++ b/HelpSource/Classes/Sieve.schelp @@ -0,0 +1,949 @@ +CLASS::Sieve +summary::Container class for sieve lists +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Tutorials/Sieves_and_Psieve_patterns, Classes/Psieve, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + +DESCRIPTION:: +Container for a list of ascending integers as 'points' or 'intervals'. For an introduction and more examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + +CLASSMETHODS:: + +method::newEmpty + +Creates a new empty Sieve object. + + +method::new + +Creates a new Sieve object in mode 'points'. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::limit +An integer limit, which is included when reached. If no limit is passed, returned integers might go up to default limit 65536. + + +method::new_i + +Creates a new Sieve object in mode 'intervals'. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::limit +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::new_o + +Creates a new Sieve object in mode 'points' with offset. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. + +argument::offset +An Integer. + +argument::limit +An integer limit, which is included when reached. If no limit is passed, returned integers might go up to default limit 65536. + + +method::new_oi + +Creates a new Sieve object in mode 'intervals' with offset. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. + +argument::offset +An Integer. + +argument::limit +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + + +method::union + +Creates a new Sieve object in mode 'points', generated by the union of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + + +method::union_i + +Creates a new Sieve object in mode 'intervals', generated by the union of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::union_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the union of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::union_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the union of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::sect + +Creates a new Sieve object in mode 'points', generated by the intersection of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::sect_i + +Creates a new Sieve object in mode 'intervals', generated by the intersection of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::sect_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the intersection of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::sect_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the intersection of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::symdif + +Creates a new Sieve object in mode 'points', generated by the symmetrical difference of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::symdif_i + +Creates a new Sieve object in mode 'intervals', generated by the symmetrical difference of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::symdif_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the symmetrical difference of sets integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::symdif_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the symmetrical difference of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::dif + +Creates a new Sieve object in mode 'points', generated by the difference of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::dif_i + +Creates a new Sieve object in mode 'intervals', generated by the difference of sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::dif_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the difference of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::dif_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the difference of sets of integers. + +argument::... data +Alternating generators and integer offsets plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + +method::limit + +Get the global limit of Class Sieve. +Set the global limit of Class Sieve to an integer value. + + + +INSTANCEMETHODS:: + +method::union + +Creates a new Sieve object in mode 'points', generated by the union of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::| + +Binary operator for instance method strong::union::. Creates a new Sieve object in mode 'points', generated by the union of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Returned integers might go up to default limit 65536. + + +method::union_i + +Creates a new Sieve object in mode 'intervals', generated by the union of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::|* + +Binary operator for instance method strong::union_i::. Creates a new Sieve object in mode 'intervals', generated by the union of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Integer intervals might be collected up to default summation limit of 65536. + + + +method::union_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the union of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + + +method::union_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the union of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::sect + +Creates a new Sieve object in mode 'points', generated by the intersection of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::& + +Binary operator for instance method strong::sect::. Creates a new Sieve object in mode 'points', generated by the intersection of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Returned integers might go up to default limit 65536. + + + +method::sect_i + +Creates a new Sieve object in mode 'intervals', generated by the intersection of the receiver and sets of integers. + + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + + +method::&* + +Binary operator for instance method strong::sect_i::. Creates a new Sieve object in mode 'intervals', generated by the intersection of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Integer intervals might be collected up to default summation limit of 65536. + + +method::sect_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the intersection of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::sect_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the intersection of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::symdif + +Creates a new Sieve object in mode 'points', generated by the symmetrical difference of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::-- + +Binary operator for instance method strong::symdif::. Creates a new Sieve object in mode 'points', generated by the symmetric difference of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Returned integers might go up to default limit 65536. + + +method::symdif_i + +Creates a new Sieve object in mode 'intervals', generated by the symmetrical difference of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + +method::--* + +Binary operator for instance method strong:: symdif_i::. Creates a new Sieve object in mode 'intervals', generated by the symmetric difference of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Integer intervals might be collected up to default summation limit of 65536. + + +method::symdif_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the symmetrical difference of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, returned integers might go up to default limit 65536. + + +method::symdif_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the symmetrical difference of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals are collected up to default summation limit of 65536. + + + +method::dif + +Creates a new Sieve object in mode 'points', generated by the difference of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + +method::- + +Binary operator for instance method strong::dif::. Creates a new Sieve object in mode 'points', generated by the difference of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Returned integers might go up to default limit 65536. + + + +method::dif_i + +Creates a new Sieve object in mode 'intervals', generated by the difference of the receiver and sets of integers. + +argument::... data +Generators and an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + +method::-* + +Binary operator for instance method strong:: dif_i::. Creates a new Sieve object in mode 'intervals', generated by the difference of the receiver and a generator. + +argument::gen +A generator. Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +Integer intervals might be collected up to default summation limit of 65536. + + +method::dif_o + +Creates a new Sieve object in mode 'points' with offsets, generated by the difference of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce zero and its positive multiples. +If no limit is passed, returned integers might go up to default limit 65536. + +method::dif_oi + +Creates a new Sieve object in mode 'intervals' with offsets, generated by the difference of the receiver and sets of integers. + +argument::... data +Alternating integer offsets and generators plus an optional integer limit, wrapped into a Ref, which is included when reached. +Allowed generators: Integers, Streams or Patterns producing intervals or Sieves itself. +Integers and Stream/Pattern output must be strictly positive. +Integers as generators produce constant intervals. +If no limit is passed, integer intervals might be collected up to default summation limit of 65536. + + + +method::plot + +Plot the Sieve's list. + + + +method::size + +The Sieve's list size. + + +method::toPoints + +Convert the Sieve to mode 'points' and set first point to offset. + + +method::toIntervals + +Convert the Sieve to mode 'intervals' and set offset to first point. + + +method::shift + +Shift the Sieve's list by strong::addOffset::. + +argument::addOffset +An Integer. + + +method::>> + +Binary operator for instance method strong::shift::. Shift the Sieve's list by strong::addOffset::. + +argument::addOffset +An Integer. + + +method::shiftTo + +Shift the Sieve's list to strong::targetOffset::. + +argument::targetOffset +An Integer. + + +method::>>! + +Binary operator for instance method strong::shiftTo::. Shift the Sieve's list to strong::targetOffset::. + +argument::targetOffset +An Integer. + + +method::shiftToZero + +Shift the Sieve's list to offset zero. + + +method::weakCopy + +Returns a new Sieve with same list object. + + +method::copy + +Returns a new Sieve with copied list object. + + +method::copyWith + +Takes over mode and offset from receiver and passes an appropriate SequenceableCollection. + +argument::seqCollection +SequenceableCollection. + +argument::withCheck +Boolean. Determines if strong::seqCollection:: is checked according to mode. +Defaults to true. + + +method::copyApplyTo + +Apply operator (Symbol of method or Function) to the Sieve's list and pass the result to a new Sieve with copied mode and offset. + +argument::operator +Symbol of method or Function. + +argument::withCheck +Boolean. Determines if result of the operation is checked according to mode. +Defaults to true. + + +method::== + +Equality check. Sieves of different mode are equal iff the lists resulting from conversion are equal. + +argument::that +Object to compare. + + +method::segmentGreaterEqual + +Returns a new Sieve of mode 'points' with Integers greater than or equal strong::lo::. + +argument::lo +Integer. + + +method::>=! + +Binary operator for strong::segmentGreaterEqual::. + +argument::lo +Integer. + + + +method::segmentGreater + +Returns a new Sieve of mode 'points' with Integers greater than strong::lo::. + +argument::lo +Integer. + + +method::>! + +Binary operator for strong::segmentGreater::. + +argument::lo +Integer. + + +method::segmentLessEqual + +Returns a new Sieve of mode 'points' with Integers less than or equal strong::hi::. + +argument::hi +Integer. + + +method::<=! + +Binary operator for strong::segmentLessEqual::. + +argument::hi +Integer. + + +method::segmentLess + +Returns a new Sieve of mode 'points' with Integers less than strong::hi::. + +argument::hi +Integer. + + +method::=! + +Binary operator for strong::segmentBetweenEqual::. + +argument::bounds +Must be an array with integers lo and hi. + + + +method::segmentBetween + +Returns a new Sieve of mode 'points' with Integers greater than strong::lo:: and less than strong::hi::. +This method is more efficient than applying strong::segmentGreater:: plus strong::segmentLess::. + +argument::lo +Integer. + +argument::hi +Integer. + + + +method::<>! + +Binary operator for strong::segmentBetween::. + +argument::bounds +Must be an array with integers lo and hi. + + + +method::checkSymmetricPeriods + +Checks the list of a Sieve for symmetric periods and returns an array strong::[periods, symmetries, completions]::, +where periods is the clumped list of strong::periods::, strong::symmetries:: a corresponding array of Symbols and +strong::completions:: a corresponding array of Booleans, indicating if periods are complete. +strong::periods:: can contains Symbols strong::'sym'::, strong::'asym'::, strong::'quasisym':: and strong::'identic'::. +See link::Tutorials/Sieves_and_Psieve_patterns#3b:: for a characterisation of these types. +It is assumed that the receiver has a periodic list, changes between periodic and +aperiodic segments are not detected, so also aperiodic prefixes of periodic lists. + + +method::checkCharacteristicPeriod + +Checks the first complete period based on the data returned by strong::checkSymmetricPeriods::. +It returns an array strong::[characteristicPeriod, offset, oddEven, symmetry]::, where +strong::characteristicPeriod:: denotes the first complete period, strong::offset:: the index at which it starts +in the receiver's list, strong::oddEven:: one of the Symbols 'odd' and 'even' and strong::symmetry:: the +symmetry type as in strong::checkSymmetricPeriods::. + + +method::plotCharacteristicPeriod + +Plots the characteristic period returned by strong::checkCharacteristicPeriod::. + + +method::list + +Get the Sieve's list. + + +method::offset + +Get the Sieve's offset. + + +method:: mode + +Get the Sieve's mode. + + + +private:: miSC_setMode, miSC_setOffset, miSC_setList, miSC_sieveOp, miSC_checkOffsetArgs, miSC_checkArgs, miSC_streamifySieveItems + + + +SECTION::Examples + +code:: +// instantiation with 'new' + +Sieve.new(1000) + +Sieve.new(4, 20) + +Sieve.new_i(4, 20) + +Sieve.new_o(4, 1, 20) + +Sieve.new_oi(4, 1, 20) + + + +// instantiation with union +// collecting multiples resp. shifted multiples +// limit must be wrapped into a Ref object + +Sieve.union(4, 7, `20) + +Sieve.union_i(4, 7, `20) + +Sieve.union_o(4, 1, 7, -1, `20) + +Sieve.union_oi(4, 1, 7, -1, `20) + + + +// instantiation with intersection +// collecting least common multiples (lcms) resp. shifted lcms + +Sieve.sect(4, 3, `30) + +Sieve.sect_i(4, 3, `30) + +Sieve.sect_o(4, -1, 3, 0, `30) + +Sieve.sect_oi(4, -1, 3, 0, `30) + + + +// instantiation with symmetrical difference +// equals union without intersection, thus multiples without lcms + +Sieve.symdif(4, 3, `30) + +Sieve.symdif_i(4, 3, `30) + +Sieve.symdif_o(4, -1, 3, 0, `30) + +Sieve.symdif_oi(4, -1, 3, 0, `30) + + +// all take more arguments + +Sieve.union(4, 5, 7, `30) + +Sieve.symdif(4, 5, 7, `30) + + + +// difference is not symmetrical, but subtrahends can be swapped + +Sieve.dif(4, 3, 7, `30) + +Sieve.dif(3, 4, 7, `30) + +Sieve.dif(3, 7, 4, `30) + + + +// corresponding instance methods and its binary operators + +a = Sieve(4, 30); + +b = Sieve(3, 30); + +a.union(b) + +a|b + +a.union_i(b) + +a|*b + + +// here first arg is offset of receiver + +a.union_o(0, b, 100) + +a.union_oi(0, b, 100) + + +a.sect(8) + +a & 8 + +a.sect_i(8) + +a &* 8 + + +a.sect_o(1, b, 5) + +a.sect_oi(1, b, 5) + + +a.symdif(b) + +a -- b + +a.symdif_i(b) + +a --* b + + +a.dif(b) + +a - b + +a.dif_i(b) + +a -* b + +:: + +For conversion, segmentation and transformation examples see link::Tutorials/Sieves_and_Psieve_patterns::. + + + + diff --git a/HelpSource/Classes/SimpleNumber.ext.schelp b/HelpSource/Classes/SimpleNumber.ext.schelp new file mode 100644 index 0000000..8205654 --- /dev/null +++ b/HelpSource/Classes/SimpleNumber.ext.schelp @@ -0,0 +1,5 @@ + +INSTANCEMETHODS:: + + +private:: miSC_specAsArray, miSC_decimalStrings \ No newline at end of file diff --git a/HelpSource/Classes/SkipJack.ext.schelp b/HelpSource/Classes/SkipJack.ext.schelp new file mode 100644 index 0000000..a57bb7f --- /dev/null +++ b/HelpSource/Classes/SkipJack.ext.schelp @@ -0,0 +1,5 @@ + +INSTANCEMETHODS:: + +private:: miSC_cleanup + diff --git a/HelpSource/Classes/SmoothClipQ.schelp b/HelpSource/Classes/SmoothClipQ.schelp new file mode 100644 index 0000000..4939c05 --- /dev/null +++ b/HelpSource/Classes/SmoothClipQ.schelp @@ -0,0 +1,65 @@ +CLASS:: SmoothClipQ +summary:: wave shaping / clipping pseudo ugen using parabolic segments +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Tutorials/Smooth_Clipping_and_Folding, Classes/SmoothClipS, Classes/SmoothFoldS, Classes/SmoothFoldQ, Classes/SmoothFoldS2, Classes/SmoothFoldQ2 + + +DESCRIPTION:: + +Wave shaping with parabolic segments at borders. The strong::amount:: of smoothness can be controlled: 0 means a linear transfer function, 1 a full parabolic segment, values inbetween a transfer function which consists of a line and a parabolic segment. For strong::amount:: > 0 the slope of the transfer function equals 0 at the borders. + +CLASSMETHODS:: + +method::ar + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::amount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if lo = hi and the border case of strong::amount = 1::). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +method::kr + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::amount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if lo = hi and the border case of strong::amount = 1::). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// control smoothness + +x = { SmoothClipQ.ar(LFTri.ar(300, 0, 0.25), -0.2, 0.2, MouseX.kr(0, 1)) }.scope + +x.release +:: + diff --git a/HelpSource/Classes/SmoothClipS.schelp b/HelpSource/Classes/SmoothClipS.schelp new file mode 100644 index 0000000..f75b545 --- /dev/null +++ b/HelpSource/Classes/SmoothClipS.schelp @@ -0,0 +1,65 @@ +CLASS:: SmoothClipS +summary:: wave shaping / clipping pseudo ugen using sine segments +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Tutorials/Smooth_Clipping_and_Folding, Classes/SmoothClipQ, Classes/SmoothFoldS, Classes/SmoothFoldQ, Classes/SmoothFoldS2, Classes/SmoothFoldQ2 + + +DESCRIPTION:: + +Wave shaping with sine segments at borders. The strong::amount:: of smoothness can be controlled: 0 means a linear transfer function, 1 a full sine segment, values inbetween a transfer function which consists of a line and a sine segment. For strong::amount:: > 0 the slope of the transfer function equals 0 at the borders. + +CLASSMETHODS:: + +method::ar + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::amount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if lo = hi and the border case of strong::amount = 1::). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +method::kr + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::amount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if lo = hi and the border case of strong::amount = 1::). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// control smoothness + +x = { SmoothClipS.ar(LFTri.ar(300, 0, 0.25), -0.2, 0.2, MouseX.kr(0, 1)) }.scope + +x.release +:: + diff --git a/HelpSource/Classes/SmoothFoldQ.schelp b/HelpSource/Classes/SmoothFoldQ.schelp new file mode 100644 index 0000000..436008b --- /dev/null +++ b/HelpSource/Classes/SmoothFoldQ.schelp @@ -0,0 +1,72 @@ +CLASS:: SmoothFoldQ +summary:: wave folding pseudo ugen using parabolic segments +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Tutorials/Smooth_Clipping_and_Folding, Classes/SmoothClipS, Classes/SmoothClipQ, Classes/SmoothFoldS, Classes/SmoothFoldS2, Classes/SmoothFoldQ2 + + +DESCRIPTION:: + +Wave folding using SmoothClipQ. Values outside the range strong::lo::-strong::hi:: are folded back, if foldRange > 0. A larger strong::foldRange:: means less folding whereas a smaller strong::foldRange:: causes more folding. The spectral result depends on the source wave form also but in general a smaller strong::foldRange:: causes more energy in the higher spectrum whereas near strong::foldRange:: == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced. + +CLASSMETHODS:: + +method::ar + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::foldRange +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the ranges near both borders, which are used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +method::kr + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::foldRange +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the ranges near both borders, which are used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// see scope, MouseX controls foldRange, MouseY smoothAmount + +x = { SmoothFoldQ.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0.2, 0.8), MouseY.kr(0, 1)) }.scope + +x.release +:: + diff --git a/HelpSource/Classes/SmoothFoldQ2.schelp b/HelpSource/Classes/SmoothFoldQ2.schelp new file mode 100644 index 0000000..a22f43c --- /dev/null +++ b/HelpSource/Classes/SmoothFoldQ2.schelp @@ -0,0 +1,82 @@ +CLASS:: SmoothFoldQ2 +summary:: wave folding pseudo ugen using parabolic segments, two fold ranges +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Tutorials/Smooth_Clipping_and_Folding, Classes/SmoothClipS, Classes/SmoothClipQ, Classes/SmoothFoldS, Classes/SmoothFoldQ, Classes/SmoothFoldS2 + + +DESCRIPTION:: + +Wave folding using SmoothClipQ. Values outside the range strong::lo::-strong::hi:: are folded back, if the concerned foldRange > 0. A larger foldRange means less folding whereas a smaller foldRange causes more folding. The spectral result depends on the source wave form also but in general a smaller foldRange causes more energy in the higher spectrum whereas near foldRange == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced. + +CLASSMETHODS:: + +method::ar + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + + +argument::foldRangeLo +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values below strong::lo::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::lo::, which is used for folding, defaults to 1. + +argument::foldRangeHi +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values above strong::hi::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::hi::, which is used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +method::kr + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + + +argument::foldRangeLo +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values below strong::lo::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::lo::, which is used for folding, defaults to 1. + +argument::foldRangeHi +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values above strong::hi::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::hi::, which is used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// see scope, MouseX controls foldRangeLo, MouseY foldRangeHi + +x = { SmoothFoldQ2.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0, 1), MouseY.kr(0, 1)) }.scope + +x.release + +:: + diff --git a/HelpSource/Classes/SmoothFoldS.schelp b/HelpSource/Classes/SmoothFoldS.schelp new file mode 100644 index 0000000..0bf91a4 --- /dev/null +++ b/HelpSource/Classes/SmoothFoldS.schelp @@ -0,0 +1,72 @@ +CLASS:: SmoothFoldS +summary:: wave folding pseudo ugen using sine segments +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Tutorials/Smooth_Clipping_and_Folding, Classes/SmoothClipS, Classes/SmoothClipQ, Classes/SmoothFoldQ, Classes/SmoothFoldS2, Classes/SmoothFoldQ2 + + +DESCRIPTION:: + +Wave folding using SmoothClipS. Values outside the range strong::lo::-strong::hi:: are folded back, if foldRange > 0. A larger strong::foldRange:: means less folding whereas a smaller strong::foldRange:: causes more folding. The spectral result depends on the source wave form also but in general a smaller strong::foldRange:: causes more energy in the higher spectrum whereas near strong::foldRange:: == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced. + +CLASSMETHODS:: + +method::ar + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::foldRange +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the ranges near both borders, which are used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +method::kr + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + +argument::foldRange +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the ranges near both borders, which are used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// see scope, MouseX controls foldRange, MouseY smoothAmount + +x = { SmoothFoldS.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0.2, 0.8), MouseY.kr(0, 1)) }.scope + +x.release +:: + diff --git a/HelpSource/Classes/SmoothFoldS2.schelp b/HelpSource/Classes/SmoothFoldS2.schelp new file mode 100644 index 0000000..edc0efd --- /dev/null +++ b/HelpSource/Classes/SmoothFoldS2.schelp @@ -0,0 +1,81 @@ +CLASS:: SmoothFoldS2 +summary:: wave folding pseudo ugen using sine segments, two fold ranges +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Tutorials/Smooth_Clipping_and_Folding, Classes/SmoothClipS, Classes/SmoothClipQ, Classes/SmoothFoldS, Classes/SmoothFoldQ, Classes/SmoothFoldQ2 + + +DESCRIPTION:: + +Wave folding using SmoothClipS. Values outside the range strong::lo::-strong::hi:: are folded back, if the concerned foldRange > 0. A larger foldRange means less folding whereas a smaller foldRange causes more folding. The spectral result depends on the source wave form also but in general a smaller foldRange causes more energy in the higher spectrum whereas near foldRange == 0 the higher part of the spectrum again decreases. Note that, in contrast to classical wave folding, the number of foldings isn't limited here, possibly causing aliasing when heavy folding is forced. + +CLASSMETHODS:: + +method::ar + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + + +argument::foldRangeLo +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values below strong::lo::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::lo::, which is used for folding, defaults to 1. + +argument::foldRangeHi +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values above strong::hi::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::hi::, which is used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + +method::kr + +argument::in +input signal. + +argument::lo +lower limit, defaults to -1. + +argument::hi +upper limit, defaults to 1. + + +argument::foldRangeLo +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values below strong::lo::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::lo::, which is used for folding, defaults to 1. + +argument::foldRangeHi +the relative amount of the range (defined by strong::lo:: and strong::hi::) used for folding back values above strong::hi::, should be >= 0 and <= 1. 0 means no folding (just smooth clipping), 1 means that the full range is used for folding, values inbetween determine the range near strong::hi::, which is used for folding, defaults to 1. + +argument::smoothAmount +amount of smoothness, must be >= 0 and <= 1, defaults to 0.5. + +argument::delta +Threshold for avoiding zero divisions (which would happen if strong::lo:: = strong::hi:: and the border case of strong::amount:: = 1). Normally not to be set by the user, except for very small clipping ranges, defaults to 0.00001. + + + +EXAMPLES:: + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// see scope, MouseX controls foldRangeLo, MouseY foldRangeHi + +x = { SmoothFoldS2.ar(SinOsc.ar(90), -0.1, 0.1, MouseX.kr(0, 1), MouseY.kr(0, 1)) }.scope + +x.release + +:: + diff --git a/HelpSource/Classes/Stream.ext.schelp b/HelpSource/Classes/Stream.ext.schelp new file mode 100644 index 0000000..bd3e786 --- /dev/null +++ b/HelpSource/Classes/Stream.ext.schelp @@ -0,0 +1,10 @@ + +INSTANCEMETHODS:: + +method:: asESP +Abbreviation for asEventStreamPlayer + +private:: miSC_repTypeFactor + +private:: miSC_streamifySieveItems + diff --git a/HelpSource/Classes/String.ext.schelp b/HelpSource/Classes/String.ext.schelp new file mode 100644 index 0000000..2531398 --- /dev/null +++ b/HelpSource/Classes/String.ext.schelp @@ -0,0 +1,26 @@ + +INSTANCEMETHODS:: + +private:: miSC_specAsArray, miSC_defNameAsArray + + +method:: pfuncPbinds +See link::Classes/Symbol#-pfuncPbinds::, link::Tutorials/VarGui_shortcut_builds:: + +method:: sVarGuiSpecs +See link::Classes/Symbol#-sVarGuiSpecs::, link::Tutorials/VarGui_shortcut_builds:: + + +method:: pVarGuiSpecs +See link::Classes/Symbol#-pVarGuiSpecs::, link::Tutorials/VarGui_shortcut_builds:: + + + +method:: sVarGui +See link::Classes/Symbol#-sVarGui::, link::Tutorials/VarGui_shortcut_builds:: + + +method:: pVarGui +See link::Classes/Symbol#-pVarGui::, link::Tutorials/VarGui_shortcut_builds:: + + diff --git a/HelpSource/Classes/Symbol.ext.schelp b/HelpSource/Classes/Symbol.ext.schelp new file mode 100644 index 0000000..9600bed --- /dev/null +++ b/HelpSource/Classes/Symbol.ext.schelp @@ -0,0 +1,212 @@ + +INSTANCEMETHODS:: + +private:: miSC_getCtrIndex, miSC_getEnvir + +private:: miSC_specAsArray, miSC_expandCtrs, miSC_expandCtrPairs, miSC_findGlobalControlSpec, miSC_getControlTuples, miSC_controlsToExclude, miSC_sVarGuiSpecsFromTuples, miSC_pVarGuiData + +private:: miSC_checkPbindFxBusMatch + + +method:: sVarGui +See link::Tutorials/VarGui_shortcut_builds::. Instantiate a VarGui object for control of one or more Synth(s) derived from a SynthDef name which may also be given as String. Per default controlspecs are taken from metadata definition, if defined with the SynthDef, or the global dictionary Spec.specs. Controls can be excluded with strong::exclude::, added with strong::ctrBefore:: or strong::ctrAfter:: and replaced with strong::ctrReplace::, this is also the order of operations. + +argument::ctrBefore +a spec pair collection of the form strong::[ key, spec, ...:: strong::]:: where strong::key:: is the symbol of the control arg to be set and strong::spec:: can be a collection of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: defining the corresponding ControlSpec, a Symbol / String to look for a ControlSpec in the global dictionary Spec.specs or a collection of specs of this form for an arrayed control. May also be a SimpleNumber for a dummy slider with fixed value. Defaults to nil. Also takes a Function of indices that returns a valid arg. + +argument::ctrReplace +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::ctrAfter +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::exclude +a collection of control keys (Symbols) to be excluded. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::metaKey +Symbol. Key to lookup SynthDef metadata. Also takes a Function of indices that returns a Symbol. Defaults to \specs. + +argument::useGlobalSpecs +Boolean. Defines if to consider global ControlSpecs if metadata is not given. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::num +Boolean. Integer. Number of Synths to be controlled. Defaults to 1. + +argument::server +Server. Defaults to the default server. + + + + + +method:: pVarGui +See link::Tutorials/VarGui_shortcut_builds::. Instantiate a VarGui object for control of one or more Pbind(s) / EventStreamPlayer(s), derived from a SynthDef name which may also be given as String. One or more Pbind(s) with Pfunc pairs and the corresponding environmental variable controls are generated, controls for duration and legato are added. Per default controlspecs are taken from metadata definition, if defined with the SynthDef, or the global dictionary Spec.specs. Controls can be excluded with strong::exclude::, added with strong::ctrBefore:: or strong::ctrAfter:: and replaced with strong::ctrReplace::; Pbind pairs can be excluded with strong::exclude::, added with strong::pBefore:: or strong::pAfter::: and replaced with strong::pReplace::, this is the order of operations for Synths and Pbind pairs. Note that strong::exclude:: applies to Synth controls and Pbind pairs. If an added Pbind pair with key \degree, \note or \midinote is detected, \freq is excluded automatically from Pbind and controls. Gate control is excluded per default. + +argument::ctrBefore +a spec pair collection of the form strong::[ key, spec, ...:: strong::]:: where strong::key:: is the symbol of the environmental variable to be set and strong::spec:: can be a collection of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: defining the corresponding ControlSpec, a Symbol / String to look for a ControlSpec in the global dictionary Spec.specs or a collection of specs of this form for an arrayed control if the environmental variable should have the value of a collection itself. May also be a SimpleNumber for a dummy slider with fixed value. Defaults to nil. Also takes a Function of indices that returns a valid arg. + +argument::ctrReplace +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::ctrAfter +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + + +argument::durCtr +a controlspec of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: or a Symbol / String to look for a ControlSpec in the global dictionary Spec.specs. Also takes a Function of indices that returns a valid arg. Defaults to #[0.05, 3, \exp, 0, 0.2]. + + +argument::legatoCtr +a controlspec of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: or a Symbol / String to look for a ControlSpec in the global dictionary Spec.specs. Also takes a Function of indices that returns a valid arg. Defaults to #[0.1, 5, \exp, 0, 0.8]. + +argument::pBefore +a Pbind pair collection of the form strong::[ key, patterns, ...:: strong::]::. Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. + +argument::pReplace +a Pbind pair collection of the form strong::[ key, patterns, ...:: strong::]::. Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. + +argument::pAfter +a Pbind pair collection of the form strong::[ key, patterns, ...:: strong::]::. Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. + +argument::exclude +a control key (Symbol) or a collection of control keys to be excluded from Pbind pairs and controls. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::excludeGate +Boolean. Determines if gate control should be excluded. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::clock +TempoClock, nil or collection thereof for playing streams. Also takes a Function of indices that returns a valid arg. Defaults to the default TempoClock. + +argument::quant +Quant, Float, nil or collection thereof used as quant data for playing streams. Also takes a Function of indices that returns a valid arg. Defaults to Quant.default (none). + +argument::metaKey +Symbol. Key to lookup SynthDef metadata. Also takes a Function of indices that returns a Symbol. Defaults to \specs. + +argument::useGlobalSpecs +Boolean. Defines if to consider global ControlSpecs if metadata is not given. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::post +Boolean. Determines if to post order of Pbind pairs. Also takes a Function of indices that returns a Boolean. Defaults to false. + +argument::trace +Boolean. Determines if EventStreamPlayer should post Events when playing. Also takes a Function of indices that returns a Boolean. Defaults to false. + +argument::num +Integer. Number of Pbinds / EventStreamPlayers to be controlled. Defaults to 1. + + + + +method:: sVarGuiSpecs +See link::Tutorials/VarGui_shortcut_builds::. Generate control data for one or more Synth(s) derived from a SynthDef name which may also be given as String. Returns a grouped collection, also for num = 1. Data can directly been used as input to VarGui's synthCtr arg. This method can be used for control of Synths derived from more than one SynthDef in one VarGui or combined control of Synths and Pbinds / EventStreamPlayers. + +argument::ctrBefore +a spec pair collection of the form strong::[ key, spec, ...:: strong::]:: where strong::key:: is the symbol of the control arg to be set and strong::spec:: can be a collection of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: defining the corresponding ControlSpec, a Symbol / String to look for a ControlSpec in the global dictionary Spec.specs or a collection of specs of this form for an arrayed control. May also be a SimpleNumber for a dummy slider with fixed value. Defaults to nil. Also takes a Function of indices that returns a valid arg. + +argument::ctrReplace +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::ctrAfter +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::exclude +a collection of control keys (Symbols) to be excluded. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::metaKey +Symbol. Key to lookup SynthDef metadata. Also takes a Function of indices that returns a Symbol. Defaults to \specs. + +argument::useGlobalSpecs +Boolean. Defines if to consider global ControlSpecs if metadata is not given. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::num +Boolean. Integer. Number of Synths to be controlled. Defaults to 1. + + + + + +method:: pVarGuiSpecs +See link::Tutorials/VarGui_shortcut_builds::. Generate envir variable control data for one or more Environments derived from a SynthDef name which may also be given as String. Returns a grouped collection, also for num = 1. Data can directly been used as input to VarGui's varCtr arg. This method can be used for control of Pbinds / EventStreamPlayers derived from more than one SynthDef in one VarGui or combined control of Synths and Pbinds / EventStreamPlayers. + + +argument::ctrBefore +a spec pair collection of the form strong::[ key, spec, ...:: strong::]:: where strong::key:: is the symbol of the environmental variable to be set and strong::spec:: can be a collection of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: defining the corresponding ControlSpec, a Symbol / String to look for a ControlSpec in the global dictionary Spec.specs or a collection of specs of this form for an arrayed control if the environmental variable should have the value of a collection itself. May also be a SimpleNumber for a dummy slider with fixed value. Defaults to nil. Also takes a Function of indices that returns a valid arg. + +argument::ctrReplace +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::ctrAfter +a spec pair collection of a form like strong::ctrBefore::. Also takes a Function of indices that returns a valid arg. Defaults to nil. + + +argument::durCtr +a controlspec of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: or a Symbol to look for a ControlSpec in the global dictionary Spec.specs. Also takes a Function of indices that returns a valid arg. Defaults to #[0.05, 3, \exp, 0, 0.2]. + + +argument::legatoCtr +a controlspec of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]:: or a Symbol to look for a ControlSpec in the global dictionary Spec.specs. Also takes a Function of indices that returns a valid arg. Defaults to #[0.1, 5, \exp, 0, 0.8]. + +argument::exclude +a control key (Symbol) or a collection of control keys to be excluded from Pbind pairs and controls. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::excludeGate +Boolean. Determines if gate control should be excluded. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::metaKey +Symbol. Key to lookup SynthDef metadata. Also takes a Function of indices that returns a Symbol. Defaults to \specs. + +argument::useGlobalSpecs +Boolean. Defines if to consider global ControlSpecs if metadata is not given. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::num +Integer. Number of Pbinds / EventStreamPlayers to be controlled. Defaults to 1. + + + + + +method:: pfuncPbinds +See link::Tutorials/VarGui_shortcut_builds::. Generate Pbinds with Pfunc pairs derived from corresponding SynthDef metadata resp. global ControlSpecs. Duration and legato pairs are added by default. If an added Pbind pair with key \degree, \note or \midinote is detected, \freq is excluded automatically. Returns a collection, also for num = 1. + + +argument::pBefore +a Pbind pair collection of the form strong::[ key, patterns, ...:: strong::]::. Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. + +argument::pReplace +a Pbind pair collection of the form strong::[ key, patterns, ...:: strong::]::. Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. + +argument::pAfter +a Pbind pair collection of the form strong::[ key, patterns, ...:: strong::]::. Also takes a Function of indices that returns a Pbind pair collection. Defaults to nil. + +argument::exclude +a control key (Symbol) or a collection of control keys to be excluded from Pbind pairs and controls. Also takes a Function of indices that returns a valid arg. Defaults to nil. + +argument::excludeGate +Boolean. Determines if gate control should be excluded. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument:: excludeDur +Boolean. Determines if \dur should be excluded from the Pbind. Also takes a Function of indices that returns a Boolean. Defaults to false. + +argument:: excludeLegato +Boolean. Determines if \legato should be excluded from the Pbind. Also takes a Function of indices that returns a Boolean. Defaults to false. + +argument::metaKey +Symbol. Key to lookup SynthDef metadata. Also takes a Function of indices that returns a Symbol. Defaults to \specs. + +argument::useGlobalSpecs +Boolean. Defines if to consider global ControlSpecs if metadata is not given. Also takes a Function of indices that returns a Boolean. Defaults to true. + +argument::post +Boolean. Determines if to post order of Pbind pairs. Also takes a Function of indices that returns a Boolean. Defaults to false. + +argument::trace +Boolean. Determines if EventStreamPlayer should post Events when playing. Also takes a Function of indices that returns a Boolean. Defaults to false. + +argument::num +Integer. Number of Pbinds / EventStreamPlayers to be controlled. Defaults to 1. + + + + + diff --git a/HelpSource/Classes/Synth.ext.schelp b/HelpSource/Classes/Synth.ext.schelp new file mode 100644 index 0000000..a52f187 --- /dev/null +++ b/HelpSource/Classes/Synth.ext.schelp @@ -0,0 +1,7 @@ + +INSTANCEMETHODS:: + +private:: miSC_getCtrIndex + +private:: miSC_getParentHelpSynth, miSC_isGeneratedByHelpSynth + diff --git a/HelpSource/Classes/TZeroXBufRd.schelp b/HelpSource/Classes/TZeroXBufRd.schelp new file mode 100755 index 0000000..9f18603 --- /dev/null +++ b/HelpSource/Classes/TZeroXBufRd.schelp @@ -0,0 +1,718 @@ +CLASS:: TZeroXBufRd +summary:: triggers sequences of segments between zero crossings from one or more buffers with demand-rate control +categories:: Libraries>miSCellaneous>ZeroX ugens +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/ZeroXBufRd, Classes/ZeroXBufWr, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies + +DESCRIPTION:: + +TZeroXBufRd is for triggering possibly overlapped segments between zero crossings (half wavesets) from one or more buffers, whereby several reading and processing parameters can be sequenced with demand rate ugens. Full waveset sequences can so be generated as a special case. It needs analysis data prepared with link::Classes/ZeroXBufWr::. For consecutive reading of segments between zero crossings see link::Classes/ZeroXBufRd::. ZeroXBufRd / TZeroXBufRd can be used for a number of synthesis / processing techniques in a field between wavesets [1, 4, 5], pulsar synthesis [1, 3], buffer modulation and rectification (which are both a kind of waveshaping) and stochastic concatenation methods [2, 6]. There are already existing SC waveset implementations like Alberto de Campo's Wavesets quark (https://github.com/supercollider-quarks/quarks) and Olaf Hochherz's SPList (https://github.com/olafklingt/SPList), which do language-side analysis and Fabian Seidl's RTWaveSets plugin (https://github.com/tai-studio/RTWaveSets). My focus has been server-side analysis and demand rate ugen control of half waveset parameters as well as multichannel and buffer switch options. Realtime control while analysis is possible, as long as reading is only refering to already analysed sections, but clearly most flexibility is given with a fully analysed buffer, which can also be done in quasi realtime. + +note:: +Depending on the multichannel sizes and the options used (rate and dir sequencing) it might be necessary to increase server resources, i.e. the number of interconnect buffers and / or memory size (e.g. s.options.numWireBufs = 256; s.options.memSize = 8192 * 32; s.reboot). Because of overlappings this is more relevant with TZeroXBufRd than with ZeroXBufRd. +:: + +note:: +Often it pays to adjust zero crossings in the sound buffer effectively to 0, that way sawtooth-like interpolation artefacts can be avoided. See link::#Ex. 1#Ex. 1:: and link::Classes/ZeroXBufRd#Ex. 7::. +:: + +note:: +Demand rate UGens in ZeroXBufRd / TZeroXBufRd must always use inf as repeats arg, this is of course not necessary for nested ones. You might pass a length arg though (link::#Ex. 5#Ex. 5::). +:: + +note:: +The distance between triggers must remain above control duration, otherwise the synthesis fails. For faster trigerring you'd have to use the server with a lower blocksize. +:: + +note:: +As triggered half wavesets can overlap you'd have to care for a sufficiently large 'overlapSIze' arg. See link::#Ex. 3#Ex. 3:: for possible estimations. +:: + +note:: +For avoiding too long half wavesets it might be useful to apply LeakDC resp. a high pass filter before analysis. +:: + +note:: +In rare cases I noticed corrupted buffers in multi buffer examples for no obvious reason. +:: + +subsection::Credits +Thanks to Tommaso Settimi for an inspiring discussion, which gave me a nudge to tackle these classes. + + +subsection::References + +numberedList:: + +## de Campo, Alberto. "Microsound" In: Wilson, S., Cottle, D. and Collins, N. (eds). 2011. The SuperCollider Book. Cambridge, MA: MIT Press, 463-504. + +## Luque, Sergio (2006). Stochastic Synthesis, Origins and Extensions. Institute of Sonology, Royal Conservatory, The Netherlands. https://sergioluque.com + +## Roads, Curtis (2001). Microsound. Cambridge, MA: MIT Press. + +## Seidl, Fabian (2016). Granularsynthese mit Wavesets für Live-Anwendungen. Master Thesis, TU Berlin. https://www2.ak.tu-berlin.de/~akgroup/ak_pub/abschlussarbeiten/2016/Seidl_MasA.pdf + +## Wishart, Trevor (1994). Audible Design. York: Orpheus The Pantomime Ltd. + +## Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition. + +:: + + + +CLASSMETHODS:: + + +method::ar + +Creates a new TZeroXBufRd ar UGen. + + +argument::sndBuf +Buffer or SequenceableCollection of Buffers to read the data from, data must correspond to strong::zeroXBuf::. + +argument::zeroXBuf +Analysis Buffer resp. SequenceableCollection of such, prepared with link::Classes/ZeroXBufWr::. Must refer to data passed to strong::sndBuf::. + +argument::bufMix +A Number indicating the strong::sndBuf:: index, a demand rate or other ugens returning strong::sndBuf:: indices or a SequenceableCollection of such. If strong::bufMix:: equals nil (default) the size of the returned signal equals the size of strong::sndBuf::, otherwise it equals its own size. + +argument::trig +A trigger signal for starting new half waveset groups. + + +argument::zeroX +A Number indicating the index in strong::zeroXBuf::, a demand rate or other ugens returning strong::zeroXBuf:: indices or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::zeroX:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 0. + +argument::xNum +Determining the number of half wavesets starting at strong::zeroX::, a demand rate or other ugens returning these numbers or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::xNum:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + +argument::xRep +Determining the number of repetitions of half wavesets resp. half waveset groups (given by strong::xNum::) starting at strong::zeroX::, a demand rate or other ugens returning these numbers or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::xRep:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + + +argument::power +Used for processing the buffer signal according to the formula: sig ** strong::power:: * strong::mul:: + strong::add:: per half waveset. Must be a positive Number, a demand rate or other ugens returning strong::power:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + +argument::mul +Used for processing the buffer signal according to the formula: sig ** strong::power:: * strong::mul:: + strong::add:: per half waveset. Must be a Number, a demand rate or other ugens returning strong::mul:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::mul:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + +argument::add +Used for processing the buffer signal according to the formula: sig ** strong::power:: * strong::mul:: + strong::add:: per half waveset. Must be a Number, a demand rate or other ugens returning strong::add:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::add:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 0. + + +argument::rate +Determines the playback rate per half waveset together with strong::rateMul::. Must be a positive Number, a demand rate or other ugens returning strong::rate:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::rate:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + +argument::dir +Determines the playback direction of half wavesets. Must be +1 or -1, a demand rate or other ugens returning strong::dir:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::dir:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + + +argument::interpl +Determines the interpolation type for the BufRd ugens. Must equal 1 (no), 2 (linear) or 4 (cubic) or a SequenceableCollection of these numbers. Defaults to 4. + +argument::overlapSize +Determines the maximum overlap of half waveset groups. This is a fixed number or a SequenceableCollection thereof determining the size of internally used multichannel signals for overlappings. If this number is too low the synthesis fails. See link::#Ex. 3#Ex.3:: for estimating a sufficiently large value. Defaults to 10. + + +argument::length +Determines the number of triggers before release of the overall asr envelope. Can be a Sequenceable Collection too. Overruled by strong::maxTime:: if this is reached before. Defaults to inf. + +argument::maxTime +Determines the time before release of the overall asr envelope. Can be a Sequenceable Collection too. Overruled by strong::length:: if this is reached before. Defaults to inf. + +argument::att +Attack time of overall asr envelope or SequenceableCollection thereof. Defaults to 0. + +argument::rel +Release time of overall asr envelope or SequenceableCollection thereof. Defaults to 0. + +argument::curve +Curve of overall asr envelope or SequenceableCollection thereof. Defaults to -4. + +argument::doneAction +Done action of overall asr envelope or SequenceableCollection thereof. Defaults to 0. + + + + +section::Examples + +See also the examples of link::Classes/ZeroXBufRd:: help. Most features work in the same way, this help file focusses rather on the differences. + + + +anchor::Ex. 1:: +subsection::Ex. 1: Basic usage + + +code:: +// prepare two short buffers for audio and zero crossing data +// the size of needed zeroX data space can be roughly estimated + +( +b = Buffer.alloc(s, 256); +z = Buffer.alloc(s, 32); +) + +// analyse a short snippet of modulation + +( +x = { + var src = SinOsc.ar(SinOsc.ar(1200, 0, 1000, 100)) * SinOsc.ar(700) - 0.1; + ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, doneAction: 2); + Silent.ar +}.play +) + + +// check the waveform + +b.plot + + + +// It's important to note that the maximum trigger rate should be below control rate, +// otherwise sequencing with demand rate ugens is messed up. +// This limitation can be circumvented by rebooting the server with a lower blockSize. + +// demand rate ugens in TZeroXBufRd should always use inf as repeats arg + +( +~maxTrigRate = s.sampleRate / s.options.blockSize; + +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(MouseX.kr(10, ~maxTrigRate)), + zeroX: Dseq([2, 3], inf), + rate: 0.2 + ) * 0.1 +}.play +) + +s.scope + +x.release + +// In this example waveforms are slightly crossing the x axis. +// This comes from the fact that buffer values at zero crossing positions are not equal zero, +// but just of a different sign than the sample before. +// The effect is also explained in ZeroXBufRd's help Ex.7. + +( +{ + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(150), + zeroX: Dseq([2, 3], inf), + rate: 0.2 + ) * 0.2 +}.plot(0.03) +) + + +// To get cleaner waveforms it's therefore recommended to adjust zero crossings in the buffer. +// This can also be done while analysis by using the flag 'adjustZeroXs' in ZeroXBufWr. + +b.adjustZeroXs(z) + + +// smoother result + +( +{ + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(150), + zeroX: Dseq([2, 3], inf), + rate: 0.2 + ) * 0.2 +}.plot(0.03) +) + + +// mul and dir can be used in the same way as with ZeroXBufRd + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(MouseX.kr(30, ~maxTrigRate)), + zeroX: Dseq([2, 3], inf) + LFDNoise0.ar(10).range(0, 5), + mul: Dseq([0.05, 0.1, 0.35], inf), + rate: 0.5, + dir: Dseq([1, -1], inf), + ) +}.play +) + +x.release + + +// unlike with ZeroXBufRd with rate there's no restriction for using +// combinations of demand rate and normal ugens + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(MouseX.kr(30, ~maxTrigRate)), + zeroX: Dseq([2, 3], inf), + mul: Dseq([0.05, 0.1, 0.35], inf), + rate: Dseq([0.2, 0.5, 1], inf) * SinOsc.ar(5).range(0.8, 1.2), + dir: Dseq([1, -1], inf), + ) +}.play +) + +x.release + + +// power arg +// be careful with this arg moving away from 1 ! +// high power values can result in loud signals if the source has values outside [-1, 1] and +// small power values can also become loud with source values near zero + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(MouseX.kr(30, ~maxTrigRate)), + zeroX: Dseq([2, 3], inf), + power: MouseY.kr(0.3, 2), + rate: 0.2, + dir: Dseq([1, 1, 1, -1], inf), + ).tanh * 0.3 +}.play +) + +x.release +:: + + + +anchor::Ex. 2:: +subsection::Ex. 2: The 'xNum' and 'xRep' args + + +code:: +// needs Buffers from Ex.1 + +// With ZeroXBufRd repetitions of (groups of) half wavesets can easily be defined +// with passing appropriate demand rate ugens to the zeroX arg. +// With TZeroXBufRd the situation is different as the use of an external trigger +// opens the freedom to specify the sequences of such groups independently. + +// The following plots show the options in the case of non-overlapping groups. + + +// Half waveset and full waveset at indices 2 and 3 + +( +{ + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(100), + xNum: Dseq([1, 2], inf), + zeroX: Dseq([2, 3], inf), + rate: 0.2 + ); +}.plot(0.03) +) + +// Repeated half wavesets + +( +{ + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(50), + xRep: 3, + zeroX: Dseq([2, 3], inf), + rate: 0.2 + ); +}.plot(0.05) +) + + +// Sequencing half waveset number and repetitions + +( +{ + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(50), + xNum: Dseq([1, 2, 3], inf), + xRep: Dseq([3, 2, 1], inf), + zeroX: Dseq([2, 3], inf), + rate: 0.2 + ); +}.plot(0.14) +) +:: + + + + +anchor::Ex. 3:: +subsection::Ex. 3: The 'overlapSize' arg + +code:: +// TZeroXBufRd enables overlappings of half wavesets, the maximum number of +// overlaps is given with the non-modulatable arg 'overlapSize' which defaults to 10. +// So if waveset groups are too long and/or the trigger rate is too high +// groups will be cut and the synthesis, according to the other passed args, fails. + +// Supposed constant values, the minimum necessary overlapSize can be calculated +// by the formula: + +// ceiling((wavesetGroupSampleNum * trigRate) / (sampleRate * rate)) + +// where wavesetGroupSampleNum means the number of samples of a group, +// which consists of xNum * xRep half wavesets. + + +// It's the user's responsibility to care for a sufficiently large overlapSize, +// resp. sufficiently low trigger rates, xNum and xRep args as well as not too low playback rates. +// With recorded sounds it might be necessary to estimate the largest half wavesets +// by analysis in the language. + +// An easy way to reduce the maximum and average half waveset length is +// repeating the zeroX analysis with a LeakDC or high pass filter applied. + + +// Buffers from Ex.1 +// We suppose a sample rate of 44100 + +b.loadToFloatArray(action: { |b| v = b }) + +z.loadToFloatArray(action: { |b| w = b }) + +// zero crossing analysis data + +w + +// with zeroX = 1 and xNum = 7 we have a chunk of 194 samples + +w[8] - w[1] + + +// according to the above formula, with a trigger rate of 500 and +// a playback rate of 0.5 the minimal necessary overlapSize is 5 + +194 * 500 / (44100 * 0.5) + +-> 4.3990929705215 + +// check with overlapSizes of 5 (or higher), +// it's the same and sounding smooth, +// with overlapSize = 4 the result is erroneous, resp. distorted + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(500), + zeroX: 1, + xNum: 7, + rate: 0.5, + overlapSize: 5, + ) * 0.1 +}.play +) + +s.scope + +x.release +:: + + +anchor::Ex. 4:: +subsection::Ex. 4: Multichannel usage and the 'bufMix' arg + +code:: +// This is very simliar to the conventions of ZeroXBufRd, +// buffers can be switched per trigger. + +// Without passing a bufMix arg the size of the returned signal is determined by the buffer input. +// It may be a single channel buffer or an array of single channel buffers, +// in correspondence with the analysis buffer(s) - multichannel buffers are not allowed. +// If bufMix is passed, it determines the size of the returned signal, +// its components can be demand rate or other ugens to control switching between buffers per half waveset groups. + +// Note: buffer switching can become CPU-demanding with a lot of Buffers +// as for fast switching it is necessary to play all in parallel + +( +// boot with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.options.memSize = 8192 * 32; +s.reboot; +) + + +// prepare 3 buffers + +( +b = { Buffer.alloc(s, 1000, 1) } ! 3; +z = { Buffer.alloc(s, 100, 1) } ! 3; +) + +// fill with basic waveforms +( +{ + var src = [ + SinOsc.ar(400), + LFTri.ar(400), + SinOsc.ar(400) ** 10 + ]; + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2); + Silent.ar +}.play +) + + +s.scope + +// play 2 channels with sine and triangle, where +// triangle is alternating between half and full waveset + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(100), + xNum: [2, Dseq([1, 2], inf)], + zeroX: 0, + bufMix: [0, 1] + ) * 0.1 +}.play +) + +x.release + + +// sequencing repetitions +// if both channels should get the same sequence wrap demand rate ugen into a Function + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(100), + xNum: 1, + xRep: { Dseq((1..5), inf) }, + zeroX: 0, + bufMix: [0, 1], + rate: 0.7 + ) * 0.1 +}.play +) + +x.release + + +// overlapping groups + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(100), + xNum: 1, + xRep: [Dseq((1..15), inf), Dseq((15..1), inf)], + zeroX: 0, + bufMix: [0, 1], + rate: MouseX.kr(0.2, 3), + overlapSize: 10 + ) * 0.1 +}.play +) + +x.release + + +// estimate the maximum xRep for the given overlapSize, +// in the above example (suppose samplerate 44100): +// as the buffers have been generated with freq = 400, +// we can roughly estimate the half wavesets with 55 samples. + +// According to the formula of Ex. 2 + +55 * xRep * 100 / (44100 * 0.2) = 10 + +xRep = (44100 * 0.2) * 10 / (55 * 100) + +-> 16.036363636364 + +// so with xRep values up to 17 we get a bit of distortion besides the aliasing (hardly audible), +// it gets stronger with lower overlapSize and disappears with higher values + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(100), + xNum: 1, + xRep: [Dseq((1..17), inf), Dseq((17..1), inf)], + zeroX: 1, + bufMix: [0, 1], + rate: 0.2, + overlapSize: 10 // check with higher and lower values + ) * 0.1 +}.play +) + +x.release + + + +// alternating buffers in one channel +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(100), + xNum: 2, + xRep: 1, + zeroX: 1, + bufMix: Dseq([0, 1], inf), + rate: 0.6, + ) * 0.1 +}.play +) + +x.release + + +// various sequences in both channels with switched waveforms + +( +x = { + TZeroXBufRd.ar( + b, z, + trig: Impulse.ar(200), + xNum: [Dseq([1, 2], inf), Dseq([2, 1], inf)], + xRep: [Dseq([1, 2], inf), Dseq([2, 1], inf)], + zeroX: 0, + bufMix: [Dseq([0, 1, 2], inf), Dseq([1, 2, 0], inf)], + rate: MouseX.kr(0.2, 2), + ) * 0.1 +}.play +) + +x.release +:: + + +anchor::Ex. 5:: +subsection::Ex. 5: The overall envelope + + +code:: +// This works also like for ZeroXBufRd, 'length' refers to the maximum number of triggers for half waveset groups. + +// The finishing of a TZeroXBufRd is not detemined by finite demand rate ugens but by an overall envelope, +// its release section is triggered by a maximum number of half wavesets ('length') or a maximum time. + +// Buffers from Ex.4 + +{ TZeroXBufRd.ar(b[0], z[0], trig: Impulse.ar(500), rate: 1, length: 10, rel: 0.01) }.plot(0.05) + +{ TZeroXBufRd.ar(b[0], z[0], trig: Impulse.ar(500), rate: 1, maxTime: 0.02, rel: 0.01) }.plot(0.05) + + +// envelopes can be differentiated + +{ TZeroXBufRd.ar(b[0..1], z[0..1], trig: Impulse.ar(500), rate: 1, maxTime: [0.01, 0.005], rel: [0.005, 0.02]) }.plot(0.03) + +{ TZeroXBufRd.ar(b[0..1], z[0..1], trig: Impulse.ar(500), rate: 1, length: [7, 2], rel: [0.005, 0.02]) }.plot(0.03) + + +// there should be only one doneAction 2 in this case + +{ TZeroXBufRd.ar(b[0..1], z[0..1], trig: Impulse.ar(500), rate: 1, maxTime: [0.01, 0.005], rel: [0.05, 0.5], doneAction: [0, 2]) }.play + + +( +b.do(_.free); +z.do(_.free); +) +:: + + +anchor::Ex. 6:: +subsection::Ex. 6: Simultaneous writing and reading + + +code:: +// The reading of half wavesets can start before analysis is finished, +// if TZeroXBufRd is carefully used in with a bit of delay. +// A bit more delicate than with ZeroXBufRd because of the independent trigger. + + +// prepare buffers + +( +p = Platform.resourceDir +/+ "sounds/a11wlk01.wav"; +b = Buffer.read(s, p); +) + +( +z = Buffer.alloc(s, b.duration * 44100 / 5, 1); +s.scope; +) + + +// Simultaneous writing and reading is easier with ZeroXBufRd +// as the trigger deltas are given by the source then. + +( +{ + var src = PlayBuf.ar(1, b, BufRateScale.ir(b)); + // write zero crossings, but no need to overwrite sound buffer + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, writeSndBuf: 0); + DelayL.ar( + TZeroXBufRd.ar( + b, z, + // indicating stereo + bufMix: [0, 0], + // one trigger for both channels + // sufficiently slow progress for the given source + // (can not be guaranteed for an arbitrary signal) + trig: TDuty.ar(Dstutter(5, Dseq([1, 5, 10], inf)) * ControlDur.ir), + xNum: 1, + xRep: 2, + // stereo, drate ugens must be wrapped + zeroX: { Dseries() }, + rate: { Dwhite(0.5, 0.7) }, + maxTime: 7, + rel: 1, + doneAction: 2 + ), + 0.1, + 0.1 + ); +}.play +) + +( +b.free; +z.free; +) + +// It's of course unproblematic – and still quasi realtime – to fully a analyse +// a snippet of sound with ZeroXBufWr before freely using TZeroXBufRd in the same synth +:: + + + +anchor::Ex. 7:: +subsection::Ex. 7: Granulation with movement through a buffer + + +See link::Tutorials/Buffer_Granulation#Ex.1h:: + + diff --git a/HelpSource/Classes/TempoClock.ext.schelp b/HelpSource/Classes/TempoClock.ext.schelp new file mode 100644 index 0000000..5edb332 --- /dev/null +++ b/HelpSource/Classes/TempoClock.ext.schelp @@ -0,0 +1,4 @@ + +INSTANCEMETHODS:: + +private:: miSC_getPhaseFromNextTimeOnGrid, miSC_getPhaseFromTimeToNextBeat diff --git a/HelpSource/Classes/Thread.ext.schelp b/HelpSource/Classes/Thread.ext.schelp new file mode 100644 index 0000000..4446d3e --- /dev/null +++ b/HelpSource/Classes/Thread.ext.schelp @@ -0,0 +1,4 @@ + +INSTANCEMETHODS:: + +private:: miSC_getReceiver, miSC_getParent, miSC_getFunc, miSC_getEnvironment diff --git a/HelpSource/Classes/UGen.ext.schelp b/HelpSource/Classes/UGen.ext.schelp new file mode 100755 index 0000000..756a0d2 --- /dev/null +++ b/HelpSource/Classes/UGen.ext.schelp @@ -0,0 +1,5 @@ + +INSTANCEMETHODS:: + + +private::miSC_methodSelectorForRate diff --git a/HelpSource/Classes/VarGui.schelp b/HelpSource/Classes/VarGui.schelp new file mode 100755 index 0000000..e8ea218 --- /dev/null +++ b/HelpSource/Classes/VarGui.schelp @@ -0,0 +1,1677 @@ +CLASS:: VarGui +summary:: slider / player gui to set envir variables and synth controllers and play synths, event patterns and tasks +categories:: Libraries>miSCellaneous>GUI, GUI +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/VarGui_shortcut_builds, Tutorials/HS_with_VarGui, Tutorials/Event_patterns_and_LFOs, Tutorials/Event_patterns_and_Functions, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation + + +DESCRIPTION:: + + +SC setups may contain discrete and continuous control, e.g. using combinations of Pbinds, Tasks and Synths. There are many possible ways of interaction between such elements, sometimes there is the alternative to control things by server or language (e.g. Pbinds versus Demand Ugens) but often one needs to have both. VarGui is a multi purpose slider and player GUI, originally intended for indentifying parameters to be reused in other setups. +Pbinds and Tasks can easily refer to environmental variables - in case of Pbinds e.g. via Pfunc, Plazy, Pcollect, but more conveniently via the dynamic scope link::Tutorials/PLx_suite:: - so VarGui can control environmental variables and synth controllers. For using event patterns with functional code and the related scoping features see link::Tutorials/Event_patterns_and_Functions::. VarGui was not intended for performance, however (since miSCellaneous v0.4) it includes a player section. Players can be used in different (reset) modes, states of synths and streams are reflected by colors, it also works with wslib slider classes (link::#Ex. 8#Ex.8::). For quick GUI generation using SynthDef metadata for controlspecs and / or automatic Pbind builds see link::Tutorials/VarGui_shortcut_builds::. As both VarGui help files are quite full of details, a more general overview, including some exercises, is given in link::Guides/Introduction_to_miSCellaneous::. + + +subsection:: Some Important Issues Regarding VarGui + +VarGui allows to choose SynthDefs or Synths, Events patterns or EventStreamPlayers and Task functions or Tasks as input. It is recommended to take the more general objects (SynthDefs, Event patterns, Task functions) as then derived Synths, EventStreamPlayers and Tasks are newly generated and the latter are run in newly generated Environments. If you follow this it is very unlikely to accidentally break gui representation of data (though it's not strict MVC paradigm). + +On the other hand there are special cases when you might want to pass Synth objects / synth nodes, Tasks or EventStreamPlayers directly (e.g. link::Tutorials/HS_with_VarGui::). Then a bit more care has to be taken as, although a VarGui instance doesn't allow to poll more than one GUI window from it, nothing prevents you from refering to identical Synth objects / synth nodes, Tasks, EventsStreamPlayers or environmental variables with different VarGui instances. This is not recommended as, obviously, a possible source of confusion. + +If you are passing a Synth directly and moreover its SynthDef is not known to SynthDescLib setting a single component of an arrayed control also causes setting of all components below (no other choice at the moment, however, a very special case). + + +subsection:: GUI specific + +With miSCellaneous v0.16 (March 2017) backwards compatibility with Cocoa and SwingOSC is no longer supported, now cross-platform Qt is standard. VarGui was originally written with Cocoa as reference, though restrcitions on Qt are minor. + + +numberedList:: +## With Qt mouseDown is the hardcoded mode of player action, which anyway could be regarded as standard usage. + +## Moving several sliders in parallel (link::#Ex. 1c#Ex.1c::) works on all platforms and with wslib sliders. + +## Combined slider movement with modifier keys can differ in the necessary order of key pressing and mouse clicking. In Qt you can (and with the Cmd modifier involved you have to) press thereafter. + +## With EZSlider you can jump to a certain slider position by clicking at an arbitrary position in the slider field. With wslib sliders you can choose modes \jump and \move (link::#Ex. 8#Ex.8::). + +## Combined synth / stream player button actions with Caps-lock are currently not working with Qt. +:: + +You can list styles by code::GUI.availableStyles:: and set with code::GUI.style = \myFavoriteStyle:: + + +CLASSMETHODS:: + +method::new + +Create a new VarGui object, which holds control specifications. + + +argument::varCtr +strong::specPairs:: or a collection of strong::specPairs::, where +strong::specPairs:: is a collection of the form strong::[ key, spec, ...:: strong::]:: where +strong::key:: is the symbol of the environmental variable to be set and +strong::spec:: must be one of those: + +list:: +## Collection of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]::, defining the corresponding ControlSpec, or a collection of specs of this form for an arrayed control if the environmental variable should have the value of a collection itself. strong::step:: is used for the derivation of slider step size. + +## Symbol refering to a ControlSpec globally stored in Spec.specs or a collection thereof for arrayed control. ControlSpec.step is used for the derivation of slider step size. + +## SimpleNumber for a dummy slider with fixed value. +:: + + +If strong::specPairs:: or single components of a collection of strong::specPairs:: are nil and the corresponding strong::stream:: arg is a Symbol or String pointing to a SynthDef, it will be tried to derive controls from corresponding SynthDef metadata resp. global ControlSpecs (see link::Tutorials/VarGui_shortcut_builds::). + + +Variables are set in environments that are either given implicitely (1) or explicitely (2): + +numberedList:: +## by eventstream players / tasks passed to strong::stream:: - they are already bound to an +environment - or newly generated together with eventstream players or tasks from +patterns or functions passed to strong::stream::. + +## by strong::envir::. This allows setting of variables in Environments in case of absent stream players. +:: + +From explicit or implicit strong::envir:: input an ordered collection of non-identical environments is derived, +which, without one of the above infos, will consist of currentEnvironment only. + +list:: +## If strong::varCtr:: is already grouped as a collection of strong::specPairs:: then variables from i-th strong::specPairs:: will be set +in the i-th environment of the derived collection. +## If strong::varCtr:: is given as a flat collection and strong::specPairs:: contains no multiple keys then variables are set +in the first resp. only environment in question. +## If strong::varCtr:: is given as a flat collection and strong::specPairs:: contains multiple keys then strong::varEnvirGroups:: +is needed to map variables to environments (link::#Ex. 5a#Ex.5a::). +:: +Note that the i-th environment means the i-th non-identical environment, not necessarily +(in the case of environments implicitely given by eventstream players / tasks) the environment +of the i-th stream. +Defaults to nil. + + +argument::synthCtr +strong::specPairs:: or a collection of strong::specPairs::, where +strong::specPairs:: is a collection of the form strong::[ key, spec, ...:: strong::]:: where +strong::key:: is the symbol of the control arg to be set and +strong::spec:: must be one of those: + + +list:: +## Collection of the form strong::[:: strong::minval, maxval, warp, step, default:: strong::]::, defining the corresponding ControlSpec or a collection of specs of this form for an arrayed control. strong::step:: is used for the derivation of slider step size. + +## Symbol refering to a ControlSpec globally stored in Spec.specs or a collection thereof for arrayed control. ControlSpec.step is used for the derivation of slider step size. + +## SimpleNumber for a dummy slider with fixed value. + +:: + + +If strong::specPairs:: or single components of a collection of strong::specPairs:: are nil, it will be tried to derive controls from SynthDef metadata resp. global ControlSpecs (see link::Tutorials/VarGui_shortcut_builds::). + +list:: +## If strong::synthCtr:: is already grouped as a collection of strong::specPairs:: then controls from i-th strong::specPairs:: will be used +for setting the i-th synth. +## If strong::synthCtr:: is given as a flat collection and strong::specPairs:: contains no multiple keys then controls will be used +for setting the only synth in question. +## If strong::synthCtr:: is given as a flat collection and strong::specPairs:: contains multiple keys then strong::synthCtrGroups:: +is needed to map synth controls to synths (link::#Ex. 5b#Ex.5b::). +:: +Defaults to nil. + +argument::stream +Expects Pattern, EventStreamPlayer, Function, Task or a collection thereof, +determining the number of stream players. +Patterns / Functions are used as templates for EventStreamPlayers / Tasks in +environments generated at init time. If strong::stream:: is unequal nil variables given by +strong::varCtr:: will be set in the environments derived from it. +Size of strong::stream:: must at least equal and may exceed the number of strong::varCtr:: groups, +which (see above) may be given by strong::varCtr:: itself (if a grouped collection of strong::specPairs::) +or strong::varCtrGroups::. +Correspondence between environments of variables and eventstream / task players +is optionally indicated in the GUI - however the user is responsible for defining +patterns and task functions that really involve the variables to be set ! +Defaults to nil. + + +argument::synth +Input to which synth controls are mapped. Expects Symbol refering to a SynthDef, +Synth, nodeID or collection thereof. +Size of strong::synth:: must at least equal and may exceed the number of synthCtr groups, +which (see above) may be given by strong::synthCtr:: itself (if a grouped collection of strong::specPairs::) +or strong::synthCtrGroups::. +It is recommended to refer to "known" SynthDefs (SynthDescLib), best by +passing Symbols or also registered Synths, otherwise the correct synth state must be given +explicitely by strong::assumePlaying::, strong::assumeRunning:: resp. strong::assumeEnded::, which is a nearby +source of error and confusion. +Defaults to nil. + + +argument::clock +TempoClock, nil or collection thereof for playing streams. +Passed clocks have precedence over implicitely given clocks (running eventstream players +or tasks as strong::stream:: input) in case of resuming from pause state. +Defaults to the default TempoClock. +quant - Quant, Float, nil or collection thereof used as quant data for playing streams. +Will be used in case of resuming from pause state for running +eventstream players or tasks given as strong::stream:: input. +Defaults to Quant.default (none). + + +argument::quant +Quant, Float, nil or collection thereof used as quant data for playing streams. +Will be used in case of resuming from pause state for running +eventstream players or tasks given as strong::stream:: input. +Defaults to Quant.default (none). + + +argument::varEnvirGroups +SequenceableCollection of Collections of Integer. +Expects ordered partition of the number N of strong::specPairs:: given to strong::varCtr:: as a flat collection, +also counting multiple occurences, thus defining a mapping: variable keys -> environments. +Must be a valid partition of N (taking all integers i < N, 0 included, each only once). +Its size must not exceed the number of implicitely or explicitely given environments (see strong::varCtr::). +E.g. for 3 environments and 6 variables [[2], [0,1,5], [4,3]] would be valid. +Defaults to nil. + + +argument::envir +SequenceableCollection of Environments. +Environments to be used for variable setting in case of absent stream players, only admissible if strong::stream:: is nil. +Defaults to nil. + +argument::synthCtrGroups +SequenceableCollection of Collections of Integer. +Expects ordered partition of the number N of strong::specPairs:: given to strong::synthCtr:: as a flat collection, +also counting multiple occurences, thus defining a mapping: synth control keys -> environments. +Must be a valid partition of N (taking all integers i < N, 0 included, each only once). +Its size must not exceed the size of strong::synth::. +Defaults to nil. + + +argument::assumePlaying +Boolean, nil or collection thereof, then size must equal the number of synths given +by strong::synth:: or strong::synthCtr::. Player state information for (unregistered) synths or nodeIDs, +booleans are not accepted if corresponding items in strong::synth:: are instances of Symbol or String. +Defaults to nil. + + +argument::assumeRunning +Boolean, nil or collection thereof, then size must equal the number of synths given +by strong::synth:: or strong::synthCtr::. Player state information for (unregistered) synths or nodeIDs, +booleans are not accepted if corresponding items in strong::synth:: are instances of Symbol or String. +Defaults to nil. + +argument::assumeEnded +Boolean, nil or collection thereof, then size must equal the number of synths given +by strong::synth:: or strong::synthCtr::. Player state information for (unregistered) synths or nodeIDs, +booleans are not accepted if corresponding items in strong::synth:: are instances of Symbol or String. +Defaults to nil. + +argument::server +The server to send node messages to. +Defaults to the local server. + +discussion:: + +anchor::gt_1:: + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +Pbind defined with variable to be controlled while playing. Pfunc's function is evaluated at playtime of each Event and gets the value of the variable ~midi in the environment in which the EventStreamPlayer will be playing. + +code:: +p = Pbind(\midinote, Pfunc { ~midi } + Pseq([0, 3, 5, 7], inf), \dur, 0.2) +:: + +VarGui to set this variable. As a pattern is given as stream arg the derived EventStreamPlayer will run in a new environment which is generated at VarGui init time. + +code:: +v = VarGui([\midi, [50, 70, \lin, 1, 55]], stream: p).gui; +:: + +Try out basic slider and player functionality. + + +strong::Playing: :: + + +image::attachments/VarGui/player_1.png:: + + +Background of player button lightening yellow. Functionality of the reset button depends on the active mode. The green background of the reset mode button indicates that the reset button will reset while playing and its background will flash yellow. + +The text field on the right side indicates whether an eventstream player or a task is playing, that on the left side shows the index of the environment in which the stream is playing. This is mainly useful if more stream players and variables of same names in different environments are involved - below the players there is a toggle button to indicate the envir index in slider name fields. + +strong::Pausing: :: + + +image::attachments/VarGui/player_2.png:: + + +Now pushing the play button will resume the stream where it has been paused, pushing the reset button (if the reset mode button has green background) will reset and play the stream. + +strong::Pausing and reset: :: + + +image::attachments/VarGui/player_3.png:: + + +This state can be reached from playing, pausing or ended stream when pushing the reset button under reset mode pause (orange background). Now only the play button can play the (reset) stream. + +strong::Stream has ended: :: + + +image::attachments/VarGui/player_4.png:: + + +E.g. if an eventstream player has encountered nil, reset button's background will become red. Now it needs the reset button to go on and its action - pause or play - depends on the active mode. + + +anchor::synth_0:: + +code:: +// synth definition with raising frequency + +( +SynthDef(\synth_0, { |devFactor = 0.1, devFreq = 10, amp = 0.1| + var freq = XLine.kr(400, 1200, 10); + Out.ar(0, SinOsc.ar(SinOsc.ar(devFreq, 0, devFactor * freq, freq), mul: amp).dup(2) * EnvGate.new) +}).add; +) +:: + +VarGui to play synth of above definition and set synth args, player functionality with different stop / renew modes. +Notification must be on. Note that pause, stop and resume actions cause sending of run / free messages, thus possibly audible clicks. To avoid that work with amp = 0 or use a gated envelope and a gate control slider with only values 0 and 1 or use Synths of limited duration as in Ex. 2. + +code:: +( +VarGui( + synthCtr: [\devFactor, [0, 0.99, \lin, 0.01, 0.5], + \devFreq, [1, 100, \lin, 0.1, 70], + \amp, [0, 0.3, \lin, 0.001, 0.1]], + synth: \synth_0 +).gui; +) +:: + + +Latency options (buttons and boxes below the player section): bundle latency of synth player actions can be set to nil, a custom value (button abbrieviation c) or global server latency (abbr. s), these two values can be set in the boxes below. Settings can be used to sync synth and stream players, if both contained in a GUI. + + +Synth players work similar as stream players, but there are more options. There is an addtional stop mode button that determines how and if renewing (creating new synth nodes of same definition) is handled. + +If, as above, a synth is given by a reference to a known SynthDef VarGui will start with a basicNew Synth object, indicated by white background of the synth's number field: + +image::attachments/VarGui/player_5.png:: + +Rate type (audio) is indicated in the field on the right. From this state a node on the server will be created by pause (newPaused) or play (new): + +image::attachments/VarGui/player_6.png:: + +Now playing and pausing work as usual. The red and blue background of the stop mode button indicates that the red stop button will become a blue renew button as soon as the Synth is stopped (node freed). In addition to the renew modes play (green) and pause (orange) there is also a renew mode basic new (white): + +image::attachments/VarGui/player_7.png:: + +If stop mode is set to renew (blue) the renew button will never change its function. Under renew mode play (green) every renew will free a Synth and immediately start a new (background flashing yellow): + +image::attachments/VarGui/player_8.png:: + +If stop mode is set to stop (red background), the stop / renew button will change to red: + +image::attachments/VarGui/player_9.png:: + +The renew mode button loses its function (greyed out) and stopping just frees the Synth: + +image::attachments/VarGui/player_10.png:: + +Now stop mode would have to be changed in order to play a new Synth. + + +General functionality buttons: + +image::attachments/VarGui/main_buttons.png:: + + +strong::Update:: + +Unless the VarGui window was generated with option updateNow set to false (which could be desired e.g. for a start with Synth defaults), variables and synth controls are set to slider values at gui init time, normally updating is not required. As for most uses VarGui would generate new separate environments for passed event patterns and task functions, there is no update mechanism implemented if these variables would be changed otherwise. Analagously controls of Synths played (and probably just yet generated) by a VarGui player could of course be set by means other than a VarGui slider action. Anyway both situations seem to be exceptional (you could hardly do so just by an oversight), though you can update to all slider values manually. + + +strong::Save:: + +Opens a dialog to save the current slider state as an array of four items: varCtr as flattened array of specPairs, synthCtr as flattened array of specPairs, varEnvirGroups, synthCtrGroups (which are only stored as groupings in case of multiple key occurences, nil optherwise). Player data and synth information is not stored. For loading from a file you would have to pass this (see the load method below). + + +strong::Stop:: + +Free all synths and stop all streams. You can also use modifier keys for stopping groups of players, e.g. Shift-click on a stream players's pause button to stop all streams. Freeing all synths in the same way only works if all synth players can be stopped by their stop buttons at this time. + + + +method::load + +Create a VarGui, that loads a stored slider state (strong::varCtr:: and strong::synthCtr:: data) from the specified file, which has probably been saved before via dialog. See also link::Tutorials/VarGui_shortcut_builds#6::. + +argument::pathname +Pathname string. + +argument::filename +Filename string. + +argument::stream +see link::Classes/VarGui#*new::. + +argument::synth +see link::Classes/VarGui#*new::. + +argument::clock +see link::Classes/VarGui#*new::. + +argument::quant +see link::Classes/VarGui#*new::. + +argument::varEnvirGroups +see link::Classes/VarGui#*new::. + +argument::envir +see link::Classes/VarGui#*new::. + +argument::synthCtrGroups +see link::Classes/VarGui#*new::. + +argument::assumePlaying +see link::Classes/VarGui#*new::. + +argument::assumeRunning +see link::Classes/VarGui#*new::. + +argument::assumeEnded +see link::Classes/VarGui#*new::. + +argument::server +see link::Classes/VarGui#*new::. + + +method::load_old + +Create a VarGui, that loads a stored slider state from the specified file. This is for loading slider states that have been saved with miSCellaneous v0.3 or earlier, thus ignoring the synth control slider label. Though old code examples will not necessarily work after just replacing load by load_old as other conventions have changed too. Maybe you'd also have to change strong::synth:: and strong::stream:: (former strong::players::) or add strong::assumePlaying:: and strong::assumeRunning:: args. + +argument::pathname +Pathname string. + +argument::filename +Filename string. + +argument::stream +see link::Classes/VarGui#*new::. + +argument::synth +see link::Classes/VarGui#*new::. + +argument::clock +see link::Classes/VarGui#*new::. + +argument::quant +see link::Classes/VarGui#*new::. + +argument::varEnvirGroups +see link::Classes/VarGui#*new::. + +argument::envir +see link::Classes/VarGui#*new::. + +argument::synthCtrGroups +see link::Classes/VarGui#*new::. + +argument::assumePlaying +see link::Classes/VarGui#*new::. + +argument::assumeRunning +see link::Classes/VarGui#*new::. + +argument::assumeEnded +see link::Classes/VarGui#*new::. + +argument::server +see link::Classes/VarGui#*new::. + + + +INSTANCEMETHODS:: + +private:: varCtr, synthCtr, synthIDs, server, streams, synthCtrIndices, varCtrNum, varNum, varColorNum, synthCtrNum, synthPlayerNum, streamPlayerNum, synthColorNum, varStrings, synthCtrStrings, saveData, envirs, varEnvirIndices, synthCtrSynthIndices, varEnvirGroups, synths, assumePlaying, assumeRunning, assumeEnded, streamEnvirIndices, varEnvirIndices, clocks, quants, window, playerSection, colors, varCtrColorPairs, synthCtrColorPairs, synthCtrSliders, varCtrSliders, synthNameBoxes, init, windowName, initVarCtrColorGroups, initSynthCtrColorGroups, effectiveSliderWidth, placeSliders, refreshVarCtrSliderLabels, possibleColumnBreakIndices, performVarArrayActions, performSynthArrayActions, performSliderActions, makeMsgList, updateVarSliders, updateSynthSliders, makeSaveValueMsgList, checkSingleSynthInput, checkArgs, envirFromSliderIndex, midiBindVarSlider, midiBindSynthSlider, initSynthSliderDict, initVarSliderDict, synthSliderDict, varSliderDict + +method::gui +Create a gui window. + +argument::sliderHeight +Gui slider height. Defaults to 18. + +argument::sliderWidth +Gui slider width. Depends on number of columns if not given explicitely. + +argument::labelWidth +Slider label width. Default depends on platform and gui scheme (70 or 75). + +argument::numberWidth +Slider numberbox width. Default depends on platform and gui scheme (40 or 45). + +argument::sliderType +One of the Symbols \standard, \smooth, \round. Both latter refer to EZSmoothSlider and EZRoundSlider from wslib (Quark), which needs to be installed for that choice. See link::#Ex. 8#Ex.8:: . Defaults to \standard. + +argument::sliderMode +One of the Symbols \jump, \move. Only relevant in case of sliderType \smooth or \round. Determines behaviour if slider field is clicked apart from the knob. See link::#Ex. 8#Ex.8::. Defaults to \jump. + +argument::playerHeight +Gui player height. Defaults to 18. + +argument::precisionSpan +Integer. Precision span to be regarded for representation of controlspec step. See link::#Ex. 9#Ex.9::. Defaults to 10. + +argument::stepEqualZeroDiv +Integer. Division to be assumed if controlspec step equals 0. See link::#Ex. 9#Ex.9::. Defaults to 100. + +argument::tryColumnNum +Integer. VarGui tries to arrange variable and control sliders in this number of columns if possible under the restrictions of strong::maxWindowWidth::, strong::sliderWidth::, strong::minPartitionSize:: and the following allow options. Internally a list of possible break indices is derived and then a partition as equal in size as possible is searched for. See link::#Ex. 5a#Ex.5a::, link::#Ex. 5b#Ex.5b::. Defaults to 1. + +argument::allowSynthsBreak +Boolean. Determines if all synth control sliders should be grouped within one column. +Defaults to true. + +argument::allowVarsBreak +Boolean. Determines if all variable control sliders should be grouped within one column. +Defaults to true. + +argument::allowSynthBreak +Boolean. Determines if control sliders of one synth should be grouped within one column. +Setting false only has an effect if synth controls are ordered in connected groups. +Defaults to true. + +argument::allowArrayBreak +Boolean. Determines if control sliders of an arrayed control (variable or synth) should be +grouped within one column. Defaults to true. + +argument::allowEnvirBreak +Boolean. Determines if control sliders of one environment should be grouped within one column. +Setting false only has an effect if environmental variables are ordered in connected groups. +Defaults to true. + +argument::minPartitionSize +Integer. Determines the minimum number of sliders of same type that may be grouped +in a different column. Defaults to 0. + +argument::sliderPriority +Symbol \var or \synth. Determines if variable or synth control sliders should be listed first. +Defaults to \var. + +argument::playerPriority +Symbol \stream or \synth. Determines if stream or synth players should be listed first. +Defaults to \stream. + +argument::streamPlayerGroups +Grouping of number of stream players (E.g. [[0], [1,2]] is a valid grouping of 3 players). +Defines control group for modifier option of stream playing. +Defaults to the grouping of all streamPlayers. + +argument::synthPlayerGroups +Grouping of number of synth players. +Defines control group for modifier option of synth playing. +Defaults to the grouping of all synthPlayers. + +argument::comboPlayerGroups +strong::*** currently not working *** :: + Grouping of number of synth and stream players. +Defines control group for modifier option of combined synth and stream playing. +Defaults to the grouping of all synth- and streamPlayers. + +argument::font +GUI font as String. Defaults to "Helvetica". + +argument::colorsLo +Low RGB value for color space, in which distinct slider colors for logical groups (synth, environment) +and background are chosen by random. Must be between 0 and 1. Defaults to 0.25 in color mode +and 0.4 in grey mode. + +argument::colorsHi +Hi RGB value for color space, in which distinct slider colors for logical groups (synth, environment) +and background are chosen by random. Must be between 0 and 1. Defaults to 0.7 in color mode +and 0.6 in grey mode. + +argument::colorDeviation +Nonnegative SimpleNumber. Determines the maximum amount of color deviation within a +logical slider group (synth, environment). Within the maximum deviation distinct colors are ramdomly chosen, +but arrayed controls get the same color. Defaults to 0.12 in color mode and 0 in grey mode. +ctrButtonGreyCenter - Float between 0 and 1. Determines the grey center from which button colors deviate +by the amount of strong::ctrButtonGreyDev::. Defaults to 0.5. + +argument::ctrButtonGreyCenter +Float between 0 and 1. Determines the grey center from which button colors deviate by the amount of strong::ctrButtonGreyDev::. Defaults to 0.5. + +argument::ctrButtonGreyDev +Float between 0 and 1. Determines the intensity of button colors deviating from +ctrButtonGreyCenter. Defaults to 0.8 in color mode and 0.65 in grey mode. + +argument::greyMode +Boolean. Determines if color or grey mode is chosen. Defaults to false. + +argument::varColorGroups +Grouping of colors of variable control sliders. Overrules automatic color grouping. +All indices < n (number of sliders) must occur exactly once. E.g. [[0], [1,2]] would be valid for n = 3. +See link::#Ex. 7#Ex.7::. + +argument::synthColorGroups +Grouping of colors of synth control sliders. Overrules automatic color grouping. +All indices < n (number of sliders) must occur exactly once. E.g. [[0], [1,2]] would be valid for n = 3. +See link::#Ex. 7#Ex.7::. + +argument::name +Symbol or String. Name to be displayed in the GUI window title bar. If not given explicitely types of +controls and players are indicated. + +argument::updateNow +Boolean. Determines if controls and variables should be set to slider values at GUI build time. +To keep sliders in sync with control this is done by default - however there may be cases when it is +desirable to start with other values, e.g. the synth's defaults. If set to false slider values will not be set +before the slider is moved or before all values are set by the update method or the corresponding button. + +argument::sliderFontHeight +Float. Adapts to sliderHeight if value nil is given (default). +Normally this doesn't have to be set except with very small strong::sliderHeight:: and/or certain fonts. + +argument::playerFontHeight +Float. Defaults to 12. + +argument::maxWindowWidth +Float. Defaults to 1500. + +argument::maxWindowHeight +Float. Defaults to 700. + + +anchor::gt_0:: + +discussion:: +SynthDef link::#synth_0:: from above, number of synth players multiplied by expanding single control. +For multiple slider and player button control see the modifier options explained in link::#Ex. 1c#Ex.1c::. + +code:: +( +v = VarGui( + synthCtr: [\devFactor, [0, 0.99, \lin, 0.01, 0.5], + \devFreq, [1, 100, \lin, 0.1, 70], + \amp, [0, 0.2, \lin, 0.001, 0.02]] ! 6, + synth: \synth_0 ! 6 +).gui; +) +:: + +GUI appearance customization: +close window (only one window per VarGui instance allowed) and try again with same or other color options. + +code:: +v.gui; + +v.gui(colorDeviation: 0, colorsLo: 0.4, colorsHi: 0.9); + +v.gui(greyMode: true); +:: + +Force slider arrangement in 2 columns, controls of each synth should only be in one column. + +code:: +v.gui(colorDeviation: 0, tryColumnNum: 2, allowSynthBreak: false); +:: + + +You can save a slider state snapshot by button / dialog to the file "XY", +only slider states (flattened spacPair collections) and groupings are stored, +you have to pass synth data with load. + +code:: +VarGui.load("PathToXY", "XY", synth: \synth_0 ! 6).gui; +:: + +method::update + +Update variables and controllers to current slider values. Like update button action. +Unless the VarGui window was generated with option strong::updateNow:: set to false, +variables and controllers are immediately set to slider values and normally updating is not required. + + +method::updateVarSliders + +Update variable sliders. + +argument::key +Variable name given as Symbol. + +argument::varNum +Integer. Index of variable occurence in given strong::varCtr::. Defaults to 0. + +argument::val +Float. May also be collection, then a sequence of variable sliders is set. + +argument::indexOffset +Integer. Updating will start at this index in case strong::key:: refers to arrayed control. Defaults to 0. + +argument::updateNow +Boolean. Determines if variables should immediately be updated with sliders. Defaults to true. + + +method::updateSynthSliders + +Update synth sliders. + +argument::key +Synth control name given as Symbol. + +argument::synthIndex +Integer. Index of synth in given strong::synthCtr::. Defaults to 0. + +argument::val +Float. Maybe also be collection, then a sequence of synth sliders is set. + +argument::indexOffset +Integer. Updating will start at this index in case strong::key:: refers to arrayed control. Defaults to 0. + +argument::updateNow +Boolean. Determines if synth controls should immediately be updated with sliders. Defaults to true. + + +method::font + +Set GUI font. + +argument::font +String. Defaults to "Helvetica". + +argument::sliderFontHeight +Integer. Defaults to 12. + +argument::playerFontHeight +Integer. Defaults to 12. + + +method::addSliderAction + +Add an action to be evaluated as sliderView's mouseUpAction. + +argument::function +Function. + +argument::type +Slider type, expects \var or \synth. Defaults to \var. + +argument::index +Integer. Slider index of given type. + +argument::envir +Environment where function should be evaluated. If not specified and strong::type:: equals \var the environment associated with the variable will be taken. + + +method::startMIDIlearn +Start learining mode for receiving MIDI cc messages for slider control, see link::#Ex. 10#Ex.10::. + +method::stopMIDIlearn +Stop learining mode for receiving MIDI cc messages for slider control, see link::#Ex. 10#Ex.10::. + + + + + +EXAMPLES:: + +anchor::Ex. 1a:: +subsection::Ex. 1a: step sequencer + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +There are different ways to read a sequence of values from a settable array assigned to an envir variable. PLseq is convenient, for a comparison with Plazy, Pfunc etc. see link::Tutorials/PLx_suite::. +In all cases the EventStreamPlayer can be played in an arbitrary environment, from which ~seq will be taken. This holds true for Patterns with functional code like Pfunc and also for PLseq, the latter has an envir arg which defaults to \current. +Note that all PLx Patterns default to repeats = inf, ListPatterns as Pseq default to repeats = 1. + + +code:: +( +SynthDef(\synth_1a, { |freq = 400, preAmp = 5, amp = 0.1| + var src = SinOsc.ar(freq, 0, mul: preAmp).tanh ! 2; + OffsetOut.ar(0, src * amp * EnvGen.ar(Env.perc, doneAction: 2)) +}).add; +) + +( +p = Pbind( + \instrument, \synth_1a, + \preAmp, PL(\preAmp), // or Pfunc { ~preAmp } + \amp, PL(\amp), // or Pfunc { ~amp } + \midinote, PLseq(\seq) + PL(\seqAdd), + \dur, 0.2 +); +) +:: + +code::~seq:: will be set and read in the new Environment, which will be generated at VarGui init time. + +code:: +( +~specPairs = [\seq, [36, 60, \lin, 1, 36] ! 5, + \seqAdd, [0, 12, \lin, 1, 0], + \amp, [0, 0.3, \lin, 0.01, 0.1], + \preAmp, [5, 50, \lin, 0.01, 20]]; + +v = VarGui(~specPairs, stream: p).gui; +) +:: + + +anchor::Ex. 1b:: +subsection::Ex. 1b: step sequencer with MIDI + +code:: + +( +// connect a MIDI device, allNotesOff with CmdPeriod useful + +MIDIClient.init; +m = MIDIOut(0); +g = { 16.do({ |i| m.allNotesOff(i) }) }; +CmdPeriod.add(g); + + +p = Pbind( + \type, \midi, + \midiout, m, + \chan, 0, + + \amp, PL(\amp), + \midinote, PLseq(\seq) + PL(\seqAdd), + \dur, 0.2 +); +) + +( +v = VarGui([\seq, [36, 60, \lin, 1, 36] ! 5, + \seqAdd, [0, 12, \lin, 1, 0], + \amp, [0, 1, \lin, 0.01, 0.8]], + stream: p +).gui; +) + +// remove if not needed anymore + +CmdPeriod.remove(g); + +:: + +anchor::Ex. 1c:: +subsection::Ex. 1c: more step sequencers, quantization, slider modifiers + + +SynthDef from link::#Ex. 1a#Ex.1a:: , four players from a Pbind, four varCtr specifications with shifted range. + +code:: +( +p = Pbind( + \instrument, \synth_1a, + \preAmp, PL(\preAmp), + \amp, PL(\amp), + \midinote, PLseq(\seq) + PL(\seqAdd), + \dur, 0.2 +); + +~spec = 4.collect { |i| [\seq, [12*i + 24, 12*i + 48, \lin, 1, 24*i + 36] ! 5, + \seqAdd, [0, 12, \lin, 1, 0], + \amp, [0, 0.15, \lin, 0.01, 0.07 - (0.01 * i)], + \preAmp, [5, 50, \lin, 0.01, 20]] }; +) + +// run all players in sync by passing a quant arg + +v = VarGui(~spec, stream: p!4, quant: 0.2).gui(tryColumnNum: 2, streamPlayerGroups: [[0,3], [1,2]]); + + +// EventStreamPlayers derived from Pbind are run in +// four newly generated environments, +// variables, as their names are passed four times in spec, +// are automatically set in these Environments in order. +// Envir index display can be toggled with the button on the right. + + +v.envirs; // get envirs + +// try slider action with modifier keys + +:: + +note:: + +In Qt you can press modifier keys before and thereafter. Caps-lock is currently replaced by Cmd, with Cmd modifier involved you *have* to press thereafter. + +Modifiers allow to control groups of sliders, values in other sliders are clipped to the according range. The following rules apply to synth and var control sliders separately, combined synth and var controls of same name work with Caps on cocoa and Cmd elsewise (link::#Ex. 2#Ex.2::). + + +list:: +## Shift: within an arrayed control all sliders below are set to the handled value or clipped. +## Shift + Ctrl: within an arrayed control all sliders above are set to the handled value or clipped. + +## Alt: controls of same name (in different envirs or different synths) are set to the handled value or clipped. +## Alt + Shift, Alt + Shift + Ctrl: Accordingly for arrayed controls of same name. +:: + +Modifier keys also apply to synth and stream player actions, the following to synth OR stream player combinations either: + +list:: +## Shift: button action with all players +## Shift + Ctrl: button action with all players of this state +## Shift + Alt: button action with all players of this group (if synthPlayerGroups / streamPlayerGroups was defined) +## Shift + Ctrl + Alt: button action with all players of this state and group ( --- " --- ) +:: + +:: + + +anchor::Ex. 1d:: +subsection::Ex. 1d: step sequencer, stream players in same environment + + +You can try to benefit from eventstream players having variables in common. +SynthDef from link::#Ex. 1a#Ex.1a:: , second Pbind derived from p without pitch offset as parallel pattern. + +code:: +( +p = Pbind( + \instrument, \synth_1a, + \preAmp, PL(\preAmp), + \amp, PL(\amp), + \midinote, PLseq(\seq) + PL(\seqAdd), + \dur, 0.2 +); + +q = Pbindf(p, \midinote, PLseq(\seq)); + +v = VarGui([\seq, { [48, 84, \lin, 1, rrand(48, 84)] } ! 5, + \seqAdd, [0, 12, \lin, 1, 7], + \amp, [0, 0.3, \lin, 0.01, 0.07], + \preAmp, [5, 50, \lin, 0.01, 20]], + stream: [q,p].collect(_.asESP), + // so currentEnvironment is given implicitely by both ESPs and used for setting + quant: 1 + // ensures that players, also if started separately for the first time, + // will play the sequence in sync +).gui; +) + +// stopping and resuming of a single player may break parallelism +// Shift-clicked reset syncs again + +:: + +anchor::Ex. 1e:: +subsection::Ex. 1e: step sequencer and replacements with PLx + +SynthDef from link::#Ex. 1a#Ex.1a:: + +code:: + +( +// SynthDef from (1a) + +// Pbind with PL as placeholder for pitch patterns +// master VarGui with player +// start and set seq + + +p = Pbind( + \instrument, \synth_1a, + \preAmp, PL(\preAmp), + \amp, PL(\amp), + \midinote, PL(\a) + PL(\seqAdd), + \dur, 0.2 +); + + +// ESP as stream arg: variables will be read from (build time) current Environment. + +~basePat = PLseq(\seq); +~a = ~basePat; + +v = VarGui([\seq, [36, 60, \lin, 1, 36] ! 5, + \seqAdd, [0, 12, \lin, 1, 0], + \amp, [0, 0.1, \lin, 0.001, 0.05], + \preAmp, [5, 50, \lin, 0.01, 20]], + stream: p.asESP).gui(name: \seq); + +// control spec array builder for midi range + +~pitchSpec = { |key = \seq, default = 60, step = 1, lo = 24, hi = 96| + var spec = default.asArray.collect([lo, hi, \lin, step, _]); + [key, (spec.size == 1).if { spec.flatten }{ spec }]; +}; +) + + +// replace while playing: + +// chord sequence + +( +~chordPat = PLseq(\seq) + [0, 7]; +~a = ~chordPat; +) + + +// random sequence with new VarGui for lead voice bounds + +( +VarGui(~pitchSpec.(\b, [75, 85], 0.01)).gui(name: \random); + +~randPat = Pfunc { rrand(~b[0], ~b[1]) } + [0, -13.3, -17.7]; +~a = ~randPat; +) + +// accumulation sequence with new VarGui + +( +VarGui(~pitchSpec.(\accum, { rrand(40,80) }!7 )).gui(name: \accum); + +~accPat = Ptuple( [ PL(\accum), PLseq((0..6)) ] ).collect { |x| x[0].keep(x[1]) - x[1] }; +~a = ~accPat; +) + + +// switch between PLs and set values in VarGui windows + + +~a = ~basePat; + +~a = ~chordPat; + +~a = ~randPat; + +~a = ~accPat; + +:: + +anchor::Ex. 2:: +subsection::Ex. 2: stream players and synths in one VarGui + +code:: +( +// Pbind with default synth +// ~freq can be a collection, then pitch or chord are shifted by ~freqFac, +// ascending (~step > 0) or descending (~step < 0) groups of 4 items + +p = Pbind( + \dur, 0.4, + \amp, PL(\amp), + \freq, PL(\step) ** PLseq((0..3)) * PL(\freq) * PL(\freqFac) +); + +// Synth producing an ascending line, it ends as envelope params are defined, +// end notifications will be reflected in the VarGui + +SynthDef(\synth_2, { |out = 0, freq = #[600, 700, 900, 1000], freqFac = 1, + amp = 0.1, ampFac = 0.5, preAmp = 5, attTime = 0.2, relTime = 2, susTime = 6| + var src = SinOsc.ar(freq * XLine.kr(freqFac/2, freqFac, attTime + susTime), 0, mul: preAmp).tanh ! 2; + Out.ar(0, src * amp * ampFac * EnvGen.ar(Env.linen(attTime, susTime, relTime), doneAction: 2)) +}).add; +) +:: + +Try multiple slider movements with modifier keys as described in link::#Ex. 1c#Ex.1c::. As synth args and variables are identically named they can be controlled with linked slider movements using Cmd. Accordingly stream and synth player buttons can also be pressed in parallel. + +code:: +( +v = VarGui([\freq, [600, 700, 900, 1000].collect([400, 1200, \lin, 0.01, _]), + \freqFac, [0.25, 1.25, \lin, 0.01, 1], + \amp, [0.0, 0.1, \lin, 0.001, 0.03], + \step, [0.7, 1.25, \lin, 0.01, 1.03]] ! 2, + + [\freq, [600, 700, 900, 1000].collect([400, 1200, \lin, 0.01, _]), + \freqFac, [0.25, 1.25, \lin, 0.01, 1], + \attTime, [0.02, 2, \lin, 0.01, 0.2], + \relTime, [0.02, 2, \lin, 0.01, 2], + \susTime, [0.1, 10, \lin, 0.01, 5], + \amp, [0.0, 0.1, \lin, 0.001, 0.03], + \preAmp, [5, 50, \lin, 0.01, 20]] ! 2, + + p!2, + \synth_2 ! 2, + quant: 0.4 +).gui(tryColumnNum: 2, allowSynthsBreak: false, allowEnvirBreak: false +/*, colorDeviation: 0 */ +/*, sliderPriority: \synth, playerPriority: \synth */ +) +) +:: + +anchor::Ex. 3:: +subsection::Ex. 3: granular synthesis with Tasks + +code:: +( +// Synth definition for single synthesized grains, waveform to be selected by type + +SynthDef(\synth_3, { arg out = 0, freqLo = 1000, freqHi = 10000, amp = 0.1, type = 0, pan; + var env = EnvGen.kr(Env.perc(0.001, 0.003, amp),doneAction:2), freq; + freq = Rand(freqLo, freqHi); + OffsetOut.ar(out, Pan2.ar(Select.ar(type, [FSinOsc.ar(freq), Saw.ar(freq), Pulse.ar(freq)]), pan) * env) +}).add; + +// Task function definition. Although Tasks can be passed directly to VarGui as stream arg, +// Functions have the advantage that the generated Tasks (as EventStreamPlayers with given Pbinds) +// will be played in different environments automatically. + +f = { + loop { + s.sendBundle(0.2, ["/s_new","synth_3", -1,0,0, + \out, 0, + \type, ~type, + \amp, ~amp, + \freqLo, ~freqMid / ~freqIntvl.sqrt, + \freqHi, ~freqMid * ~freqIntvl.sqrt, + \pan, [1, -1].choose * ~pan] + ); + [~durShort, ~durLong].choose.wait; + } +}; +) + + +( +v = VarGui( 3.collect { |i| [\type, [0, 2, \lin, 1, i], + \freqMid, [100, 8000, \lin, 1, 500 + (2000 * i)], + \freqIntvl, [1, 2.0, \lin, 0.01, 1.4], + \amp, [0.0, 0.2, \lin, 0.01, 0.05 * (i + 1)], + \pan, [0.0, 1.0, \lin, 0.01, 0.8], + \durShort, [0.005, 0.01, \lin, 0.001, 0.01], + \durLong, [0.01, 0.05, \lin, 0.001, 0.02] + ] }, + // f!3 doesn't collect Functions as there is already a short notation for + // collecting Function values of Integers, e.g. (_*3)!5 + stream: 3.collect { f } +).gui(colorDeviation: 0); +) +:: + + +anchor::Ex. 4a:: +subsection::Ex. 4a: interaction of synth and stream players, control synth controlling pbind synths + + +Pbind producing a sequence of short events, each pbind-driven synth reading frequency from a control bus + +code:: +( +// control synth + +SynthDef(\synth_4_kr, {|out = 0, devFreq = 0.5, midiCenter = 60, midiDev = 10| + Out.kr(out, LFDNoise3.kr(devFreq, midiDev, midiCenter)) +}).add; + +// audio synth +// mix of sine and pulse, interval, basic frequency read from control bus + +SynthDef(\synth_4_ar, {|out = 0, in = 0, soundMix = 0.5, pulseWidth = 0.5, indexLR = 0, + att = 0.005, rel = 0.1, amp = 0.1, midiInt = 3, midiAdd = 0| + var mix, freq1, freq2, fr; + freq1 = (In.kr(in, 1) + midiAdd).midicps; + freq2 = freq1 * midiInt.midicps / 0.midicps; + fr = [Select.kr(indexLR, [freq1, freq2]), Select.kr(1-indexLR, [freq1, freq2])]; + mix = (SinOsc.ar(fr, 0, amp) * (1 - soundMix)) + (Pulse.ar(fr, pulseWidth, amp) * soundMix); + Out.ar(out, EnvGen.ar(Env.perc(att, rel), doneAction: 2) * mix) +}).add; + + +x = Pbind(\instrument, \synth_4_ar, + \dur, 0.1, + \in, PL(\in), + \amp, PL(\amp), + \midiInt, Pfunc { rrand(~int[0], ~int[1]) }, // interval bounds + \rel, Pfunc { ~rel.choose }, // short and long release time + \soundMix, Pwhite(0.1, 0.9), + \indexLR, PLrand([0, 1]) +); +) + + +( +// in GUI start control synth before EventStreamPlayer +// then try playing with sliders and pausing / resuming the control synth + +c = Bus.control(s,1).index; + +VarGui([\in, [c, c, \lin, 1, c], // bus fixed, display only + \int, [3,4].collect([0, 19, \lin, 0.1, _]), + \rel, [0.01, 0.15].collect([0.01, 0.4, \lin, 0.005, _]), + \amp, [0.0, 0.3, \lin, 0.01, 0.15]], + + [\midiCenter, [45, 80, \lin, 0.1, 70], + \midiDev, [0, 20, \lin, 0.1, 20], + \devFreq, [0.1, 15, \lin, 0.1, 1], + \out, c], // bus fixed, display only + x, \synth_4_kr +).gui(sliderPriority: \synth, playerPriority: \synth) +) +:: + + +anchor::Ex. 4b:: +subsection::Ex. 4b: interaction of synth and stream players, pbind and control synth controlling audio synth + + +Audio synth controlled by LFO pitch synth and a Pbind setting synth args (like Pmono). PLx ListPatterns taken here as they default to repeats = inf. + +code:: +( +y = Pbind(\type, \set, + // sequencing of durations and amplitudes quite fixed, just global tempo and amp control + \dur, PLshufn([0.15, 0.15, 0.35]) / PL(\tempo), + \amp, PLrand([0.05, 0.12, 0.2]) * PL(\amp), + \soundMix, PLseq([0.1, 0.5, 0.9]), + \indexLR, PLrand([0, 1]), + + \midiInt, Pfunc { rrand(0, ~intMax) }, + \args, [\amp, \soundMix, \midiInt, \indexLR] // args to be set must be listed +); + + +// In GUI start control synth (#0) first, then audio synth (#1) and EventStreamPlayer, +// then try playing with sliders and pausing / resuming the control synth and EventStreamPlayer. + + +d = Bus.control(s,1).index; + +VarGui([ \tempo, [0.7, 1.2, \lin, 0.01, 1], + \amp, [0.0, 1.5, \lin, 0.01, 0.7], + \intMax, [-12, 12.0, \lin, 0.1, 8]], + + [[\midiCenter, [45, 80, \lin, 0.1, 60], + \midiDev, [0, 20, \lin, 0.1, 1.5], + \devFreq, [0.1, 15, \lin, 0.1, 10], + \out, d], // just display bus indices + [\in, d, + \out, 0, + \rel, 10000]], // ignore Env.perc definition + + y, [\synth_4_kr,\synth_4_ar] +).gui(sliderPriority: \synth, playerPriority: \synth) +) +:: + +anchor::Ex. 5a:: +subsection::Ex. 5a: reordering of var control + + +One may want to have controls grouped per name, not per Environment (resp. Pbind, Task, Synth), +this can be achieved by passing a flat (not grouped) array of specPairs and the appropriate grouping, +there are methods implemented for that special case of reordering: + +SynthDef from link::#Ex. 1a#Ex.1a:: + +code:: +( +p = Pbind( + \instrument, \synth_1a, + \preAmp, PL(\preAmp), + \amp, PL(\amp), + \midinote, Pfunc { ~midi + rrand(~midiDev.neg, ~midiDev) }, + \dur, 0.2 +); + +// flat specPairs array without multiple keys + +~specPairs = [\midi, [24, 80, \lin, 1, 36], + \midiDev, [0, 0.5, \lin, 0.01, 0.25], + \amp, [0, 0.3, \lin, 0.01, 0.1], + \preAmp, [5, 50, \lin, 0.01, 25]]; + +// get flat expansion of specPairs and appropriate groups + +~specPairsDupped = ~specPairs.specPairsDup(5).postln; +~specPairsGroups = ~specPairs.specPairsDupGroups(5); +) + + +// parallel slider movement with Alt (not an array here but identically named variables in different envirs) +// parallel player action with Shift-click + +( +v = VarGui( + ~specPairsDupped, + stream: p!5, + varEnvirGroups: ~specPairsGroups, + quant: 0.2 +).gui(colorDeviation: 0); +) + +// compare implicit mapping by passing a grouped collection of specPairs as varCtr arg + +( +v = VarGui( + ~specPairs!5, + stream: p!5, + quant: 0.2 +).gui(colorDeviation: 0); +) + +// Note that in the case of not connected varEnvirGroups the column break gui option +// allowEnvirBreak is ignored, means always set to true. + +:: + +anchor::Ex. 5b:: +subsection::Ex. 5b: reordering of synth control + +code:: +( +SynthDef(\synth_5b, { |devFactor = 0.1, devFreq = 10, amp = 0.1| + var freq = XLine.kr(2000, 400, 3); + Out.ar(0, Pan2.ar(SinOsc.ar(SinOsc.ar(devFreq, 0, devFactor * freq, freq), mul: amp), LFDNoise3.ar(2)) * EnvGate.new) +}).add; + + +~specPairs = [\devFactor, [0, 0.99, \lin, 0.01, 0.5], + \devFreq, [1, 100, \lin, 0.1, 70], + \amp, [0, 0.02, \lin, 0.001, 0.01]]; + +~num = 10; // ~num = 20; use gui args sliderHeight and tryColumnNum for larger nums + +v = VarGui( + synthCtr: ~specPairs.specPairsDup(~num), + synth: \synth_5b ! ~num, + synthCtrGroups: ~specPairs.specPairsDupGroups(~num) +).gui(colorDeviation: 0 /* ,sliderHeight: 12, tryColumnNum: 2 */); +) + +// compare implicit mapping by passing a grouped collection of specPairs as synthCtr arg + +( +~num = 10; + +v = VarGui( + synthCtr: ~specPairs ! ~num, + synth: \synth_5b ! ~num +).gui(colorDeviation: 0); +) + +// Note that in the case of not connected synthCtrGroups the column break gui option +// allowSynthBreak is ignored, means always set to true. +:: + + +anchor::Ex. 6a:: +subsection::Ex. 6a: non standard usage: passing Synths + +Passing symbols or strings as synth args, refering to known (added) SynthDefs, is recommended. +However also Synths or nodeIDs can be given, but the player would have to know their state, +so Synths should be registered. + +code:: +( +SynthDef(\sine, { |freq = 400, amp = 0.1| Out.ar(0, SinOsc.ar(freq, mul: amp)) }).add; +SynthDef(\pulse, { |freq = 400, amp = 0.1| Out.ar(0, Pulse.ar(freq, mul: amp)) }).add; +) + +( +x = Synth(\sine).register; +y = Synth(\pulse).register; +) + +// pause pulse + +y.run(false); + +// VarGui checks state, definition is known, new Synths of same definition can be started + +v = VarGui(synth: [x,y]).gui; + + +// With nodeIDs or non-registered Synths VarGui demands addtional state info + +( +x = { SinOsc.ar(400, mul: 0.1) }.play; +y = { Pulse.ar(700, mul: 0.01) }.play; +) + +y.run(false); + +// no new Synths from temporary synth definition + +v = VarGui(synth: [x,y], assumePlaying: true, assumeRunning: [true, false]).gui; + +:: + + +anchor::Ex. 6b:: +subsection::Ex. 6b: non standard usage: setting sliders from outside + +code:: +( +// synth definition with arrayed control + +SynthDef(\vibes, { |amp = 0.005, devFactor = 0.1, devFreq = 10, devDisturb = 0.1| + var freq = \midi.kr(20!30).midicps; + Out.ar(0, Mix.fill(30, {|i| [i.even.if {0}{1}, i.even.if {1}{0}] * + SinOsc.ar(SinOsc.ar(devFreq * LFDNoise3.ar(0.5, devDisturb), + 0, devFactor * freq[i], freq[i]), mul: amp) } )) +}).add; +) + + +// open gui with random midi values first, start playing + +( +v = VarGui( + synthCtr: [\devFactor, [0, 0.01, \lin, 0.001, 0.005], + \devFreq, [0, 1, \lin, 0.01, 0.5], + \devDisturb, [0, 0.99, \lin, 0.01, 0.1], + \amp, [0, 0.05, \lin, 0.001, 0.005], + \midi, 30.collect { [45.0, 95, \lin, 0.01, rrand(45,95)] } + ], + synth: \vibes +).gui; +) + + +// update whole control array with one random value +// second arg synth index + +v.updateSynthSliders(\midi, 0, rrand(50, 80.0)!30); + + +// update random group, fourth arg start index +// evaluate several times + +v.updateSynthSliders(\midi, 0, rrand(50, 80.0)!5, rrand(0,25)); + + +// phase shift gui + +( +p = Pbind( + \dur, 0.07, + \type, \rest, + \i, Pseries(), + \do, Pfunc { |e| v.updateSynthSliders(\midi, 0, (e.i / 5).sin * 25 + 70, e.i % 30) } +).play(AppClock) +) + + +// stop updating + +p.stop; + +:: + + +anchor::Ex. 6c:: +subsection::Ex. 6c: non standard usage: setting values for plotting + +code:: + +// By setting a slider hook arbitrary actions can be triggered with lifting a slider handle. +// A slider hook can e.g. trigger the refreshing of a plot of parametric functions. + +( +p = Plotter("move slider to plot", bounds: Rect(200, 200, 700, 500)); + +// number of plots in window + +n = 5; + +// VarGui with random init params + +v = VarGui({ [ + \a, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2, + \b, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2] } ! n, + envir: () ! n +).gui; + +// definition of parametric function, environment of variables will be defined later on + +f = { |x| (x * ~a[0]).sin * ~b[0] + ((x * ~a[1]).sin * ~b[1]) }; + +// evaluation points + +x = (0, 0.1..20); + +// add slider hook, index not defined, everything will be refreshed with arbitrary sliderView mouseUp + +v.addSliderAction { p.value_(v.envirs.collect { |e| f.inEnvir(e).(x) }).refresh }; + +// slider movements affecting more than one plot can be achieved with modifier combinations including alt +) + +:: + +anchor::Ex. 7:: +subsection::Ex. 7: color grouping + +code:: + +// By default color grouping is based on logical separations: +// different synths and environments, different variables and controls, arrays. + +// But apart of that there might exist more related controls +// and you'd like to overrule default color grouping. +// Especially with a large number of sliders a useful color grouping makes +// control much more convenient (also see Buffer Granulation examples). + + +// SynthDef where freq and amp controls could be grouped + +( +SynthDef(\synth_7, { |freq = 400, freqOsc = 10, freqDev = 0.03, preAmp = 5, amp = 0.1| + var src = SinOsc.ar(SinOsc.ar(freqOsc, 0, freqDev * freq, freq), 0, mul: preAmp).tanh ! 2; + Out.ar(0, src * amp * EnvGate()) +}).add; +) + + + +// The clumps method is fine for grouping + +( +~g = (0..4).clumps([3,2]); + +~synthCtr = [ + \freq, [20, 5000, \exp, 0, 80], + \freqOsc, [0, 20.0, \lin, 0, 10], + \freqDev, [0, 0.5, \lin, 0, 0.03], + \preAmp, [5, 50, \lin, 0.01, 20], + \amp, [0, 0.2, \lin, 0.01, 0.03] +]; +) + + +// GUI with one Synth + +VarGui(synth: \synth_7, synthCtr: ~synthCtr).gui(synthColorGroups: ~g); + + +// GUI with two Synths and separate colors for the second + +VarGui(synth: \synth_7!2, synthCtr: ~synthCtr!2).gui(synthColorGroups: ~g+5 ++ ~g); + + +// Duplicating colors + +( +~h = [~g, ~g+5].flop.collect(_.flat); // or ~h = ~g.collect { |x| x + 5 ++ x }; + +VarGui(synth: \synth_7!2, synthCtr: ~synthCtr!2).gui(synthColorGroups: ~h); +) + +:: + + +anchor::Ex. 8:: +subsection::Ex. 8: EZSmoothSlider, EZRoundSlider + +code:: + +// EZSlider is used as default slider type. +// With wslib installed (Quark) you can choose +// its slider types EZSmoothSlider and EZRoundSlider +// as gui option + + +VarGui(synth: \default).gui(sliderType: \smooth); + +VarGui(synth: \default).gui(sliderType: \round); + + +// you can choose from their modes \jump (\default) or \move as general option + +VarGui(synth: \default).gui(sliderType: \smooth, sliderMode: \move); + + +// if you want to set individually you can refer to sliders directly +// compare different slider behaviour of Synth 0 and 1 + +( +v = VarGui(synth: \default!2).gui(sliderType: \smooth, sliderMode: \move); + +v.synthCtrSliders.first.sliderView.mode_(\jump) +) + +// For multiple slider handling see Ex 1c. + +// Very small numbers are forced to exponential notation (see also Ex. 9). + +:: + + +anchor::Ex. 9:: +subsection::Ex. 9: slider step precision + +code:: + +// VarGui makes some adaptions concerning slider step sizes and rounding +// depending on passed controlspec step size +// in order to unify slightly different behaviour of GUI kits +// and set parameters automatically also for very small step sizes. + +// For this reason (and because of multiple slider handling) +// scaling by modifiers is disabled by default. +// You can have a finer control by moving the mouse over the NumberBox, +// this also works with modifiers for multiple sliders (Ex.1c, Ex.2). + + +VarGui([\a, [0, 1, \lin, 0.1, 0]]).gui; + +VarGui([\a, [0, 1, \lin, 0.01, 0]]).gui; + +VarGui([\a, [0, 1, \lin, 0.001, 0]]).gui; + + + +VarGui([\a, [0, 100, \lin, 1, 0]]).gui; + +VarGui([\a, [0, 10000, \lin, 10, 0]]).gui; + +VarGui([\a, [0, 10000, \lin, 100, 0]]).gui; + + +// controlspec step = 0 causes division of range by 100 + +VarGui([\a, [0, 1, \lin, 0, 0]]).gui; + +VarGui([\a, [0, 0.1, \lin, 0, 0]]).gui; + +VarGui([\a, [0, 1000, \lin, 0, 0]]).gui; + + +// division parameter can be changed + +VarGui([\a, [0, 1000, \lin, 0, 0]]).gui(stepEqualZeroDiv: 10); + +VarGui([\a, [0, 0.1, \lin, 0, 0]]).gui(stepEqualZeroDiv: 10); + + + +// in case of very long numbers it may be necessary to adapt numberWidth + +VarGui([\a, [0, 0.001, \lin, 0, 0]]).gui(numberWidth: 70); + + +// In general ranges are adapted to step size if necessary - +// this is ControlSpec's standard behaviour + +VarGui([\a, [1000, 5000, \lin, 1000.001, 0]]).gui(numberWidth: 70); + + +// a rather exotic option: +// precisionSpan defaults to 10 and fails here ... + +VarGui([\a, [10000000, 50000000, \lin, 10000000.001, 0]]).gui(numberWidth: 100); + + +// ... but resolves this + +VarGui([\a, [10000000, 50000000, \lin, 10000000.001, 0]]).gui(precisionSpan: 12, numberWidth: 100); + +:: + + + +anchor::Ex. 10:: +subsection::Ex. 10: MIDI learn functionality with sliders + + +Connect your midi device, maybe you have to restart SC then. As gui example e.g. take SynthDefs and Pbind from link::#Ex. 4a#Ex.4a::, evaluate both code blocks. It must be possible to refer to the VarGui instance (e.g. v = VarGui(...)) + + +code:: + +// start MIDI + +MIDIIn.connectAll + +// on your device define desired knobs, faders etc. to send cc messages +// probably you want to control different parameters, so define different cc numbers + +// start learning mode + +v.startMIDIlearn + + +// now assignment can happen by selecting a slider box +// it gets a focus (blue border, sometimes not very well visible) +// then send midi cc with the fader/knob of your choice +// sending data with different cc number, while the same slider is still or again selected, will overwrite + +// end of learning has to be defined + +v.stopMIDIlearn + + +// adaption of control can be done by recalling the learning mode + +v.startMIDIlearn + +... + +v.stopMIDIlearn + +:: + + + diff --git a/HelpSource/Classes/ZeroXBufRd.schelp b/HelpSource/Classes/ZeroXBufRd.schelp new file mode 100755 index 0000000..45b66e9 --- /dev/null +++ b/HelpSource/Classes/ZeroXBufRd.schelp @@ -0,0 +1,861 @@ +CLASS:: ZeroXBufRd +summary:: reads consecutive sequences of segments between zero crossings from one or more buffers with demand-rate control +categories:: Libraries>miSCellaneous>ZeroX ugens +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/TZeroXBufRd, Classes/ZeroXBufWr, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies + +DESCRIPTION:: + +ZeroXBufRd is for consecutive reading of segments between zero crossings (half wavesets) from one or more buffers, whereby several reading and processing parameters can be sequenced with demand rate ugens. Full waveset sequences can so be generated as a special case. It needs analysis data prepared with link::Classes/ZeroXBufWr::. For triggering possibly overlapped (half) wavesets see link::Classes/TZeroXBufRd::. ZeroXBufRd / TZeroXBufRd can be used for a number of synthesis / processing techniques in a field between wavesets [1, 4, 5], pulsar synthesis [1, 3], buffer modulation and rectification (which are both a kind of waveshaping) and stochastic concatenation methods [2, 6]. There are already existing SC waveset implementations like Alberto de Campo's Wavesets quark (https://github.com/supercollider-quarks/quarks) and Olaf Hochherz's SPList (https://github.com/olafklingt/SPList), which do language-side analysis and Fabian Seidl's RTWaveSets plugin (https://github.com/tai-studio/RTWaveSets). My focus has been server-side analysis and demand rate ugen control of half waveset parameters as well as multichannel and buffer switch options. Realtime control while analysis is possible, as long as reading is only refering to already analysed sections, but clearly most flexibility is given with a fully analysed buffer, which can also be done in quasi realtime. + +note:: +Depending on the multichannel sizes and the options used (rate and dir sequencing) it might be necessary to increase server resources, i.e. the number of interconnect buffers and / or memory size (e.g. s.options.numWireBufs = 256; s.options.memSize = 8192 * 32; s.reboot). Because of overlappings this is more relevant with TZeroXBufRd than with ZeroXBufRd. +:: + +note:: +Often it pays to adjust zero crossings in the sound buffer effectively to 0, that way sawtooth-like interpolation artefacts can be avoided. See link::#Ex. 7:: and link::Classes/TZeroXBufRd#Ex. 1:: and link::Classes/ZeroXBufWr#Ex. 2::. +:: + +note:: +The reading of consecutive half wavesets is implemented with Sweep and retriggering. For that reason each played back half waveset has a minimum length of 2 samples. In the case of adjusted zero crossings that immediately follow each other this can lead to flat sections of a few samples length. Normally this is irrelevant, but you might check setting ZeroXBufWr's flag 'adjustZeroXs' to 2, see link::#Ex. 7:: and link::Classes/ZeroXBufWr#Ex. 2::. +:: + +note:: +Demand rate UGens in ZeroXBufRd / TZeroXBufRd should always use inf as repeats arg, this is of course not necessary for nested ones. You might pass a length arg though (link::#Ex. 5::). +:: + +note:: +For avoiding too long half wavesets it might be useful to apply LeakDC resp. a high pass filter before analysis. +:: + +note:: +In rare cases I noticed corrupted buffers in multi buffer examples for no obvious reason. +:: + +note:: +For full functionality at least SC 3.7 is recommended (rate sequencing doesn't work in 3.6) +:: + + +subsection::Credits +Thanks to Tommaso Settimi for an inspiring discussion, which gave me a nudge to tackle these classes. + + +subsection::References + +numberedList:: + +## de Campo, Alberto. "Microsound" In: Wilson, S., Cottle, D. and Collins, N. (eds). 2011. The SuperCollider Book. Cambridge, MA: MIT Press, 463-504. + +## Luque, Sergio (2006). Stochastic Synthesis, Origins and Extensions. Institute of Sonology, Royal Conservatory, The Netherlands. https://sergioluque.com + +## Roads, Curtis (2001). Microsound. Cambridge, MA: MIT Press. + +## Seidl, Fabian (2016). Granularsynthese mit Wavesets für Live-Anwendungen. Master Thesis, TU Berlin. https://www2.ak.tu-berlin.de/~akgroup/ak_pub/abschlussarbeiten/2016/Seidl_MasA.pdf + +## Wishart, Trevor (1994). Audible Design. York: Orpheus The Pantomime Ltd. + +## Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition. + +:: + + +CLASSMETHODS:: + + +method::ar + +Creates a new ZeroXBufRd ar UGen. + + +argument::sndBuf +Buffer or SequenceableCollection of Buffers to read the data from, data must correspond to strong::zeroXBuf::. + +argument::zeroXBuf +Analysis Buffer resp. SequenceableCollection of such, prepared with link::Classes/ZeroXBufWr::. Must refer to data passed to strong::sndBuf::. + +argument::bufMix +A Number indicating the strong::sndBuf:: index, a demand rate or other ugens returning strong::sndBuf:: indices or a SequenceableCollection of such. In contrast to other args combinations of demand rate and normal ugens are not valid. If strong::bufMix:: equals nil (default) the size of the returned signal equals the size of strong::sndBuf::, otherwise it equals its own size. + +argument::zeroX +A Number indicating the index in strong::zeroXBuf::, a demand rate or other ugens returning strong::zeroXBuf:: indices or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::zeroX:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 0. + + +argument::power +Used for processing the buffer signal according to the formula: sig ** strong::power:: * strong::mul:: + strong::add:: per half waveset. Must be a positive Number, a demand rate or other ugens returning strong::power:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::power:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + +argument::mul +Used for processing the buffer signal according to the formula: sig ** strong::power:: * strong::mul:: + strong::add:: per half waveset. Must be a Number, a demand rate or other ugens returning strong::mul:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::mul:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 1. + +argument::add +Used for processing the buffer signal according to the formula: sig ** strong::power:: * strong::mul:: + strong::add:: per half waveset. Must be a Number, a demand rate or other ugens returning strong::add:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::add:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. Defaults to 0. + + +argument::rate +Determines the playback rate per half waveset together with strong::rateMul::. Must be a positive Number, a demand rate or other ugens returning strong::rate:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::rate:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. In contrast to other args combinations of demand rate and normal ugens are not valid for implementational reasons. Though you can pass a demand rate ugen here and a normal ugen to strong::rateMul:: (or vice versa) which are then multiplied per half waveset. Defaults to 1. + +argument::rateMul +Determines the playback rate per half waveset together with strong::rate::. Must be a positive Number, a demand rate or other ugens returning strong::rateMul:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::rateMul:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. In contrast to other args combinations of demand rate and normal ugens are not valid for implementational reasons. Though you can pass a normal ugen here and a demand rate ugen to strong::rate:: (or vice versa) which are then multiplied per half waveset. Defaults to 1. + +argument::dir +Determines the playback direction of half wavesets. Must be +1 or -1, a demand rate or other ugens returning strong::dir:: values or a SequenceableCollection of such. If in this case the overall multichannel size determined by strong::sndBuf:: or strong::bufMix:: is larger than the size of strong::dir:: and the latter contains demand rate ugens, they must all be wrapped into Functions for being used more than once. In contrast to other args combinations of demand rate and normal ugens are not valid. Defaults to 1. + + +argument::interpl +Determines the interpolation type for the BufRd ugens. Must equal 1 (no), 2 (linear) or 4 (cubic) or a SequenceableCollection of these numbers. Defaults to 4. + +argument::dUniqueBufSize +Determines the buffer size for Dunique objects which have to be used in the case of demand rate ugens passed to strong::rate::, strong::dir:: or strong::bufMix::. See link::#Ex. 2::. Must be an Integer or a SequenceableCollection of Integers. Defaults to 1048576. + +argument::length +Determines the number of triggers before release of the overall asr envelope. Can be a Sequenceable Collection too. Overruled by strong::maxTime:: if this is reached before. Defaults to inf. + +argument::maxTime +Determines the time before release of the overall asr envelope. Can be a Sequenceable Collection too. Overruled by strong::length:: if this is reached before. Defaults to inf. + + +argument::att +Attack time of overall asr envelope or SequenceableCollection thereof. Defaults to 0. + +argument::rel +Release time of overall asr envelope or SequenceableCollection thereof. Defaults to 0. + +argument::curve +Curve of overall asr envelope or SequenceableCollection thereof. Defaults to -4. + +argument::doneAction +Done action of overall asr envelope or SequenceableCollection thereof. Defaults to 0. + + + + +section::Examples + + +code:: +( +// boot with extended resources, might be needed for some examples +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.options.memSize = 8192 * 32; +s.reboot; +) +:: + + +anchor::Ex. 1:: +subsection::Ex. 1: Basic usage + + +code:: +( +b = Buffer.alloc(s, 2000); +z = Buffer.alloc(s, 200); +) + +// analyse a short snippet of ring modulation + +( +{ + var src = SinOsc.ar(300) * SinOsc.ar(120) + SinOsc.ar(30) * 0.1; + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2); + Silent.ar +}.play +) + + +// check the waveform + +b.plot + + + +// loop 3rd half waveset +// compare plot and scope + +x = { ZeroXBufRd.ar(b, z, zeroX: 2) }.play + +s.scope + +x.release + + +// loop a whole waveset +// demand rate ugens in ZeroXBufRd should always use inf as repeats arg + + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf)) }.play + +x.release + + +// Note that the distance between zero crossings can be very short, +// here the half waveset at index 5 (735-740) has a length of only 5 samples and the amplitude is low. + +// zero crossing indices + +z.loadToFloatArray(action: { |b| b.postln }) + + +// the signal is hardly audible, but there as freqscope shows + +x = { ZeroXBufRd.ar(b, z, zeroX: 5) }.play + +s.freqscope + +x.release + + + +// loop a group of 3 wavesets + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq((1..6), inf)) }.play + +x.release + + + +// sequence multiplier for half wavesets + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), mul: Dseq([1, 0.2], inf)) }.play + +x.release + + +// mul can be used for rectifying effects + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq((1..2), inf), mul: Dseq([0, 1, 1], inf)) }.play + +x.release + + + +// add an offset sequence, this results in a pulse-like effect + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), add: Dseq([-0.05, 0.05], inf)) * 0.5 }.play + +x.release + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), add: Dseq([0.05, -0.05], inf)) * 0.5 }.play + +x.release + + + +// half wavesets can also get a power, +// per waveset the signal is calculated according to +// sig ** power * mul + add + +// be careful with this arg moving away from 1 ! +// high power values can result in loud signals if the source has values outside [-1, 1] and +// small power values can also become loud with source values near zero + + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), power: 0.7) }.play + +x.release + + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), power: Dseq([0.8, 1.7, 1], inf)) }.play + +x.release +:: + + + +anchor::Ex. 2:: +subsection::Ex. 2: The 'rate' and 'dir' args + + +code:: +// needs Buffers from Ex.1 + +s.scope + + +// playback rates can be defined generally ... + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), rate: 2.5) }.play + +x.release + + +// ... or as sequence + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), rate: Dseq((1..3), inf)) }.play + +x.release + + +// slightly different: here the whole waveset gets one rate + +x = { ZeroXBufRd.ar(b, z, zeroX: Dseq([1, 2], inf), rate: Dstutter(2, Dseq((1..3), inf))) }.play + +x.release + + + +// with the dir argument set to -1 the half wave set is reversed + +x = { ZeroXBufRd.ar(b, z, zeroX: 7) }.play + +x.release + + +// compare scope, no audible difference here + +x = { ZeroXBufRd.ar(b, z, zeroX: 7, dir: -1) }.play + +x.release + + +// dir can also be sequenced + +x = { ZeroXBufRd.ar(b, z, zeroX: 7, dir: Dseq([1, 1, -1], inf)) }.play + +x.release + + +// When demand rate ugens are used for 'rate' or 'dir' args ZeroXBufRd employs Dunique objects. +// This means that Buffers have to be allocated for counting, and if the Buffer is full +// the synthesis fails. By default a value of 1048576 is defined for 'dUniqueBufSize'. +// This should be sufficient for at least some minutes auf audio in average use cases. + +// However with very fast triggering you might want to pass a higher value. +// With multichannel applications it might be necessary then to run the server with higher memSize. + + +// With a deliberately bad (low) size, sequencing fails after a second + +x = { ZeroXBufRd.ar(b, z, zeroX: 1, rate: Dseq([1, 2], inf), dUniqueBufSize: 1024) }.play + +x.release + +// From low values you can roughly estimate the needed dUniqueBufSize to safely run your application +// for a given time +:: + + + + +anchor::Ex. 3:: +subsection::Ex. 3: Passing ordinary UGens as args + +code:: +// needs Buffers from Ex.1 + +// values are sampled and hold for the duration of the segments + +s.scope + +x = { ZeroXBufRd.ar(b, z, zeroX: SinOsc.ar(SinOsc.ar(0.1).range(0.2, 5)).range(1, 15)) }.play + +x.release + + +// more fun with moving rates + +( +x = { + ZeroXBufRd.ar( + b, z, + zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15), + rate: SinOsc.ar(SinOsc.ar(0.3).range(0.2, 5)).exprange(1, 5) + ) ! 2 +}.play +) + +x.release + + +// warp effect with accelerating rates + +( +x = { + ZeroXBufRd.ar( + b, z, + zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15), + rate: Dseq((1..50) / 20 + 0.5, inf) + ) ! 2 +}.play +) + +x.release + + +// also combinations of demand rate and ordinary ugens are possible +// though with the exception of rate, dir and bufMix args + +( +x = { + ZeroXBufRd.ar( + b, z, + zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15), + rate: Dstutter(Dwhite(10, 100), Dwhite(0.5, 2)), + mul: Dseq([0.2, 0.2, 1], inf) * LFDNoise3.ar(5).range(1, 5) + ) ! 2 +}.play +) + +x.release + + +// for combinations of normal and demand ugens with the rate arg rateMul can be used + +( +x = { + ZeroXBufRd.ar( + b, z, + zeroX: LFDNoise3.ar(SinOsc.ar(0.1).range(1, 10)).range(1, 15), + rate: Dstutter(Dstutter(3, Dwhite(1, 5)), Dseq([0.5, 1, 1.5], inf)), + rateMul: LFDNoise3.ar(5).range(1, 5) + ) ! 2 +}.play +) + +x.release + + +// free resources + +( +b.free; +z.free; +) +:: + + +anchor::Ex. 4:: +subsection::Ex. 4: Multichannel usage and the 'bufMix' arg + +code:: +// Without passing a bufMix arg the size of the returned signal is determined by the buffer input. +// It may be a single channel buffer or an array of single channel buffers, +// in correspondence with the analysis buffer(s) - multichannel buffers are not allowed. +// If bufMix is passed, it determines the size of the returned signal, +// its components can be demand rate or other ugens to control switching between buffers per half waveset. + +// Note: buffer switching can become CPU-demanding with a lot of Buffers +// as for fast switching it is necessary to play all in parallel + +( +// boot with extended resources +s = Server.local; +Server.default = s; +s.options.numWireBufs = 256; +s.options.memSize = 8192 * 32; +s.reboot; +) + + +// prepare 3 buffers + +( +b = { Buffer.alloc(s, 1000, 1) } ! 3; +z = { Buffer.alloc(s, 100, 1) } ! 3; +) + +// fill with basic waveforms +( +{ + var src = [ + SinOsc.ar(400), + LFTri.ar(400), + SinOsc.ar(400) ** 10 + ]; + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2); + Silent.ar +}.play +) + + + +s.scope(3) + +// play 3 channels + +x = { ZeroXBufRd.ar(b, z, zeroX: 1) * 0.1 }.play + +x.release + + +// play from 1st buffer + +x = { ZeroXBufRd.ar(b, z, bufMix: 0, zeroX: Dseq([0, 1], inf)) * 0.2 }.play + +x.release + + + +// play from 3rd and 1st buffer +// to use equally defined demand rate ugens for both, wrap them into a Function + +x = { ZeroXBufRd.ar(b, z, bufMix: [2, 0], zeroX: { Dseq([0, 1], inf) }) * 0.1 }.play + +x.release + + +// play 2 channels with different zeroX sequences + +( +x = { + ZeroXBufRd.ar( + b, z, + bufMix: [1, 2], + zeroX: [Dseq([0, 0, 1], inf), Dseq([0, 1], inf)] + ) * 0.1 +}.play +) + +x.release + + + + +// buffers can be switched per half waveset + + +x = { ZeroXBufRd.ar(b, z, bufMix: Dseq([0, 1, 2], inf), zeroX: 2, mul: 0.3) }.play + +x.release + + +x = { ZeroXBufRd.ar(b, z, bufMix: Dseq([0, 1], inf), zeroX: Dseq([1, 2], inf), mul: 0.3) }.play + +x.release + + + +// Gendy-like texture + +( +x = { + ZeroXBufRd.ar( + b, z, + bufMix: { Dseq([0, 1, 2], inf) } ! 2, + zeroX: 2, + mul: 0.1, + // array of Drands with different offset + // the average of the Drand output is 50, + // so on average 1/4 is added to x + // and the harmonic relation of L:R is 5:7 -> tritone + rate: [1, 1.5].collect { |x| Drand((1..100) / 200 + x, inf) } + ) +}.play +) + +x.release + + +// bufMix determines size +// other args are expanded accordingly + +( +x = { + ZeroXBufRd.ar(b, z, + bufMix: { Dseq([0, 1, 2], inf) } ! 2, + zeroX: { Dseq([1, 2], inf) }, + mul: { Dstutter(Diwhite(1, 1000), Drand([0.01, 0.07, 0.2], inf)) }, + rate: { Dstutter(Diwhite(1, 12), Dwhite(0.1, 10)) } + ) +}.play +) + +x.release +:: + + +anchor::Ex. 5:: +subsection::Ex. 5: The overall envelope + + +code:: +// The finishing of a ZeroXBufRd is not detemined by finite demand rate ugens but by an overall envelope, +// its release section is triggered by a maximum number of half wavesets ('length') or a maximum time. + +// Buffers from Ex.4 + +{ ZeroXBufRd.ar(b[0], z[0], rate: 1, length: 10, rel: 0.01) }.plot(0.03) + +{ ZeroXBufRd.ar(b[0], z[0], rate: 1, maxTime: 0.01, rel: 0.01) }.plot(0.03) + + +// envelopes can be differentiated + +{ ZeroXBufRd.ar(b[0..1], z[0..1], rate: 1, maxTime: [0.01, 0.005], rel: [0.005, 0.02]) }.plot(0.03) + +{ ZeroXBufRd.ar(b[0..1], z[0..1], rate: 1, length: [7, 2], rel: [0.005, 0.02]) }.plot(0.03) + + +// there should be only one doneAction 2 in this case + +{ ZeroXBufRd.ar(b[0..1], z[0..1], rate: 1, maxTime: [0.01, 0.005], rel: [0.05, 0.5], doneAction: [0, 2]) }.play + + +( +b.do(_.free); +z.do(_.free); +) +:: + + +anchor::Ex. 6:: +subsection::Ex. 6: Simultaneous writing and reading + + +code:: +// The reading of half wavesets can start before analysis is finished, +// if ZeroXBufRd is carefully used in with a bit of delay. + + +// prepare buffers + +( +p = Platform.resourceDir +/+ "sounds/a11wlk01.wav"; +b = Buffer.read(s, p); +) + +( +z = Buffer.alloc(s, b.duration * 44100 / 5, 1); +s.scope; +) + + + +// Here the average playback rate equals 1 (0.8 = 4/5, 1.25 = 5/4), +// so playback will not be faster than writing. + +( +{ + var src = PlayBuf.ar(1, b, BufRateScale.ir(b)); + // write zero crossings, but no need to overwrite sound buffer + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, writeSndBuf: false); + DelayL.ar( + ZeroXBufRd.ar( + b, z, + // Dseries keeps counting through the half-filled zeroX buffer + zeroX: Dseries(), + rate: Dstutter(10, Dseq([0.8, 1, 1.25], inf)), + // estimate end time + maxTime: b.duration + 1, + doneAction: 2 + ), + 0.2, + 0.1 + ) ! 2; +}.play +) + +( +b.free; +z.free; +) + +// The same can be done with a live-generated signal or a mic input, +// but ensure that reading comes after writing ! + + +// FAILURE BY BAD DEFINITION ! +// rates are fast, so zeroX indices are referred before analysis +// resulting in garbage noise + + +( +b = { Buffer.alloc(s, 5 * 44100) } ! 2; +z = { Buffer.alloc(s, 2 * 44100) } ! 2; +) + + +( +{ + var src = LFDNoise3.ar(300 ! 2), sig; + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1); + sig = DelayL.ar( + ZeroXBufRd.ar( + b, z, + // Dseries keeps counting through the half-filled zeroX buffer + zeroX: { Dseries() }, + + rate: { Dseq((1..10) / LFDNoise3.ar(3).range(5, 10) + 1, inf) }, + mul: { Dstutter(Dwhite(50, 500), Drand([0.02, 0.1, 0.5], inf)) }, + // estimate end time + maxTime: 10, + att: 0.2, + rel: 5, + doneAction: 2 + ), + 0.2, + 0.1 + ); + LeakDC.ar(sig) +}.play +) + + + +// Reasonable realtime usage +// zeroX is deferred by stuttering, rates are sufficiently low + +( +b.do(_.zero); +z.do(_.zero); +) + + +( +{ + var src = LFDNoise3.ar(3000 ! 2); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1); + DelayL.ar( + ZeroXBufRd.ar( + b, z, + zeroX: { Dstutter(Dwhite(50, 300), Dseries()) * 2 + Dseq((1..4), inf) }, + rate: { Dseq((1..5) / LFDNoise3.ar(3).range(5, 10) + 0.5, inf) }, + mul: { Dstutter(Dwhite(50, 500), Drand([0.05, 0.3, 0.7], inf)) }, + // estimate end time + maxTime: 20, + att: 0.2, + rel: 5, + doneAction: 2 + ), + 0.2, + 0.1 + ); +}.play +) + +( +b.do(_.free); +z.do(_.free); +) +:: + + + +anchor::Ex. 7:: +subsection::Ex. 7: Adjusting zero crossings + + +code:: +// In general a half waveset isn't totally unipolar: +// Zero crossing indices indicate the change of the sign of a signal, +// so with this convention the last sample of the half waveset itself +// has a different sign. + +// This can have the consequence that, depending on the playback rate, +// sawtooth-like effects might occur. Such artefacts can be circumvented by +// adjusting buffer values at zero crossing indices to 0, +// so playback of (half) wavesets is smoothened, especially with extreme rate values. + + +( +p = Platform.resourceDir +/+ "sounds/a11wlk01.wav"; +b = Buffer.read(s, p); +z = Buffer.alloc(s, 100000); +) + +// analyse buffer +( +{ + var src = PlayBuf.ar(1, b, BufRateScale.ir(b), doneAction: 2); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, doneAction: 2); +}.play +) + +// this half waveset clearly shows the effect +// (tested with samplerate 44100) + +s.scope + +x = { ZeroXBufRd.ar(b, z, nil, 220, rate: 0.1) * 2 }.play + + +// adjust zeros, also works with arrays of Buffers +// you can apply it while running, it might take a moment though + +b.adjustZeroXs(z) + +x.release + + +// alternatively adjusting zero crossings can be chosen as option with analysis: +// set flag 'adjustZeroXs' to 1 + + +( +p = Platform.resourceDir +/+ "sounds/a11wlk01.wav"; +b = Buffer.read(s, p); +z = Buffer.alloc(s, 100000); +) + +( +{ + var src = PlayBuf.ar(1, b, BufRateScale.ir(b), doneAction: 2); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, adjustZeroXs: 1, doneAction: 2); +}.play +) + +s.scope + +x = { ZeroXBufRd.ar(b, z, nil, 220, rate: 0.1) * 2 }.play + +x.release + + +// the flag 'adjustZeroXs' can also be set to 2 +// in this case zero crossings have a minimum distance of 2 samples +// This goes along with ZeroXBufRd's convention to play one half waveset with a minimum length of 2 samples +// (otherwise it couldn't act as a trigger) + +// the difference can be observed with fast switches between signs like with WhiteNoise + +( +b = Buffer.alloc(s, 2000); +z = Buffer.alloc(s, 2000); +) + +( +{ + var src = WhiteNoise.ar(); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, adjustZeroXs: 1, doneAction: 2) * 0.2; +}.play +) + +s.scope + + +// this generates a more pulsar-like waveform with adjacent zero crossings, +// note that transitions to flat sections are smoothened by cubic interpolation + +x = { ZeroXBufRd.ar(b, z, nil, Dseq((0..50), inf), rate: 0.03) * 0.5 }.play + +x.release + + +// there are no flat sections with 'adjustZeroXs' set to 2 + +( +b.zero; +z.zero; +) + +( +{ + var src = WhiteNoise.ar(); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, adjustZeroXs: 2, doneAction: 2) * 0.2; +}.play +) + + +x = { ZeroXBufRd.ar(b, z, nil, Dseq((0..50), inf), rate: 0.03) * 0.5 }.play + +x.release +:: + + + +anchor::Ex. 8:: +subsection::Ex. 8: Granulation with movement through a buffer + +See link::Tutorials/Buffer_Granulation#Ex.1g:: + diff --git a/HelpSource/Classes/ZeroXBufWr.schelp b/HelpSource/Classes/ZeroXBufWr.schelp new file mode 100755 index 0000000..a9cd762 --- /dev/null +++ b/HelpSource/Classes/ZeroXBufWr.schelp @@ -0,0 +1,218 @@ +CLASS:: ZeroXBufWr +summary:: writes zero crossing analysis from signals to buffers +categories:: Libraries>miSCellaneous>ZeroX ugens +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies + +DESCRIPTION:: + +ZeroXBufWr analyses zero crossings from an input signal and writes the signal and the zero crossing indices to buffers. It is intended to be used with link::Classes/ZeroXBufRd:: and link::Classes/TZeroXBufRd::, see these help files for more examples. + + +note:: +Often it pays to adjust zero crossings in the sound buffer effectively to 0, that way sawtooth-like interpolation artefacts can be avoided. See link::#Ex. 2::, link::Classes/ZeroXBufRd#Ex. 7:: and link::Classes/TZeroXBufRd#Ex. 1::. +:: + +note:: +For avoiding too long half wavesets it might be useful to apply LeakDC resp. a high pass filter before analysis. +:: + +note:: +For full functionality at least SC 3.7 is recommended (adjustZeroXs set to 2 doesn't work in 3.6) +:: + +subsection::Credits +Thanks to Tommaso Settimi for an inspiring discussion, which gave me a nudge to tackle these classes. + + +CLASSMETHODS:: + + +method::ar + +Creates a new ZeroXBufWr ar UGen. + + +argument::in +Signal to be analysed, size must correspond to strong::sndBuf:: and strong::zeroXBuf::. + +argument::sndBuf +Buffer or SequenceableCollection of Buffers to write signals to, size must correspond to strong::in:: and strong::zeroXBuf::, writing can be disabled with strong::writeSndBuf::. The length of strong::sndBuf:: determines the trigger for the doneAction. + +argument::zeroXBuf +Buffer or SequenceableCollection of Buffers to write anaysis data to, size must correspond to strong::in:: and strong::sndBuf::. + +argument::startWithZeroX +Number 0 or 1 or SequenceableCollection of such, determining whether the first sample should be regarded as zero crossing. Defaults to 0. + +argument::adjustZeroXs +One of the Numbers -1, 0, 1, 2 or a SequenceableCollection of such. +list:: +##-1: indicate all zeroXs, dont't write sound buffer +##0: indicate all zeroXs, write sound buffer +##1: indicate all zeroXs, write sound buffer, set to 0 there +##2: indicate zeroXs with a minimum distance of 2, set to 0 there +:: +Actions 1 and 2 can lead to smoother half wavesets, see examples. Defaults to 0. + + +argument::doneAction +Done action be performed after the duration of the longest buffer of strong::sndBuf::. Defaults to 0. + + +section::Examples + +See the link::Classes/ZeroXBufRd:: and link::Classes/TZeroXBufRd:: help files for more examples + + +anchor::Ex. 1:: +subsection::Ex. 1: Basic usage + +code:: +// prepare two short buffers for audio and zero crossing data + +( +b = Buffer.alloc(s, 256); +z = Buffer.alloc(s, 256); +) + + +// analyse a short snippet of random noise + +( +{ + var src = LFDNoise3.ar(5000); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 0, doneAction: 2); + Silent.ar +}.play +) + +// plot buffer, most likely it doesn't start with 0 + +b.plot + +// zero crossings + +z.loadToFloatArray(action: { |b| b.postln }) + + + +// clear buffers + +( +b.zero; +z.zero; +) + + +// example with SinOsc +// other than you might expect SinOsc doesn't start with 0 +// for analysis you might want to regard the value at index 0 as zero crossing +// this can be done with the flag startWithZeroX: + +( +{ + var src = SinOsc.ar(500); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2); + Silent.ar +}.play +) + +// plot buffer, you see that it doesn't start with 0 + +b.plot + +// zero crossings including start + +z.loadToFloatArray(action: { |b| b.postln }) +:: + +anchor::Ex. 2:: +subsection::Ex. 2: Adjusting zero crossings + +code:: +( +b = Buffer.alloc(s, 128); +z = Buffer.alloc(s, 128); +) + + +s.scope + +// fill buffer + +( +{ + var src = LFPar.ar(700); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, doneAction: 2); + Silent.ar +}.play +) + + +// playing this repeated half waveset at slow rate shows that the x axis is crossed +// as the buffer's value at the zero crossing isn't exactly 0 + +x = { ZeroXBufRd.ar(b, z, nil, 1, rate: 0.2) * 0.1 }.play + +// this can be circumvented by two strategies: + +// setting to zeros from the language +// can be done while running + +b.adjustZeroXs(z) + +x.release + + +// alternatively writing can be done with the flag 'adjustZeroXs' set to 1: + +( +{ + var src = LFPar.ar(700); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, adjustZeroXs: 1, doneAction: 2); + Silent.ar +}.play +) + + +x = { ZeroXBufRd.ar(b, z, nil, 1, rate: 0.2) * 0.1 }.play + +x.release + + +// If flag 'adjustZeroXs' is set to 2, this defines the minimum distance of detected zero crossings, +// these positions in the buffer are also set to 0. +// This option can make sense in the case of sources with many fast sign switchings. + + +// here the resulting buffer can end up with sequences of zeros ... + +( +{ + var seq = Drand([1, 1, 2, 3], inf); + var src = Duty.ar(SampleDur.ir * seq, 0, Dwhite(0.1, 1) * Dseq([-1, 1], inf)); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, adjustZeroXs: 1, doneAction: 2); + Silent.ar +}.play +) + +b.plot + + +// ... whereas here we have a continuous sequence of at least minimal half wavesets + +( +{ + var seq = Drand([1, 1, 2, 3], inf); + var src = Duty.ar(SampleDur.ir * seq, 0, Dwhite(0.1, 1) * Dseq([-1, 1], inf)); + ZeroXBufWr.ar(src, b, z, startWithZeroX: 1, adjustZeroXs: 2, doneAction: 2); + Silent.ar +}.play +) + +b.plot + +// This can especially make a difference with ZeroXBufRd, as the latter works with +// a minimum half waveset length of 2 samples +:: + diff --git a/HelpSource/Classes/attachments/DXMix/sliding_ex_1.png b/HelpSource/Classes/attachments/DXMix/sliding_ex_1.png new file mode 100644 index 0000000000000000000000000000000000000000..4093b05fa0e215c81b8f8c38491f245f6a3c3c42 GIT binary patch literal 11560 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 ZP(T2ycpL>YBpV$dBcUi>BWe)zKL9Yvc;Ns5 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/DXMix/sliding_ex_3.png b/HelpSource/Classes/attachments/DXMix/sliding_ex_3.png new file mode 100644 index 0000000000000000000000000000000000000000..24cfd8a32642433e996286b2cfd2114214438f2c GIT binary patch literal 11285 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 D*flfW literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/DXMix/sliding_ex_4.png b/HelpSource/Classes/attachments/DXMix/sliding_ex_4.png new file mode 100644 index 0000000000000000000000000000000000000000..08bc72be4d4271241ef14e9af6faeb9cd55d5a3a GIT binary patch literal 11818 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/DXMix/sliding_ex_5.png b/HelpSource/Classes/attachments/DXMix/sliding_ex_5.png new file mode 100644 index 0000000000000000000000000000000000000000..ab4a86bde24cca86e2bd6828a09f49d7c6dd35ba GIT binary patch literal 10989 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/PSPdiv/PSPdiv_graph_1.png b/HelpSource/Classes/attachments/PSPdiv/PSPdiv_graph_1.png new file mode 100755 index 0000000000000000000000000000000000000000..bcd12186579a430928beaa9933e0deea258726c0 GIT binary patch literal 35624 zcmZ_#Wk6Kj`#lb$C>;W#bPgpT-6bL=-JL^scc_$fNtb|tbm`FD-7yS3bobEwkH7Ez zdEPxQ7#L=sea_yq_rBJ(uC>CI6{WE;NHCC)kg#QCKB*!hJ#Pm7?nOfZUfDC%Mv#!6 zF3>TTSu z8+%4LvK>w^E3#?IFU>Cp=1!w*zgY(5#~4-EIoa8jo#Y3UK5L*=u)LQYVbwetmK$Yz z*U$EuMONWiNk}~|)(dJ3aq2=7D{Jdq*}OLN=gPt#v~!R<)`l28P^d$Z1_~t2mFZ~{ zIZQ-5qXh7=upZ@ziL@W7y5)U{iQeq6v!5tQelI5GWJlZKVn4`0M(V0mc04%LX8`67 z-AP8r6$$A*?Z2OAUIk(vNJvyjvY*7&y)qB7JTuj2F5BBGM~B~d=p-*wQ%!1oh@kq` z!hB^E)l#Pomba7TuKpC=jZeVi@%jK;x!ploJe^9_6VGE8R@8iT2i_VPt&oFdLA`5z z+j4LzEs7RBj~lj^J&*jivuOol;8d^BUOfN$f$G&C2+2 z|NY-;0xd}EzeeMEcqo|F2K97vJ7QvwOY#?+q)7$qB~) z-3?8b`~Tk!en&s#!ubcvq)R^}{JP#Z8)8c{Z!-6;j-`|RY~7*?l^#)W?SD6AKCRv? zta%lxeq~ZPWTEuu#RK9q<=2Auwgs6uO*gkTe*Pc-qrD*pJ1Qbyz% z!+6)6h+q&>jaE4SwVxBe@#@yKG0CA&QWQnF{Y%1KSqL|tha_`tl!wt znE@$hEX+DRwJ>d(mp>+`q~v$WXMQr2zOPt`Dx6Mas0MTKpl~PtOlP0xztp9h`C~!I zea_?D*gDDKpJ;X~6!V>6tILTr@o1qYzY22n4F)c}=Z5NC3F9W<6ZT=H%q_l%!k<5l zE2EdCh?{eUGy1rm9@zTGe6b2mjD-{jDKad0ad3VXlaTV-8SmxCK6hFRdCTdr$S*%- zr@PBRI}Wio^gZO+8qLCN55g6d5f|?eWrFA>=P?dv@!=XwrLvoRV{q6w+Guv&RxDJ= z=uNZCmTmGlOb~RUll_clm3c4@W0CT*u=d6QLjo?IGxWv&BKCAM=C(h}n!jbh z2ERh^t@uf3Xb=)GD0bJ#bDlz53$0mn|9qDQL#Ce|5n?!^*Q?Vc%@DZLgydW23l3?5 z@K3>PD-}+8^p#`V;G45e=OE9)A53Jv2i3AI>OfDf+oPL{u49|)k!8nj%-emwS@V&K%oWo`#L3lZ-YtHvDJ(w8X+*PLo4dsL$Q3 zRF3O!%FT@Hqz|hPlSfhEqALOCwi~xBt!=!dHWE zxBlH)ug<}`R8FqIaxD8tN{Z{*07FsJJB9W0F|k{7x4GUJ+@ACl8>U73FH~3&T zw*t%1XCG3McScixG@Eu5emEDdUM1PXm?rSv4uQ{QIGxPRbTs`cz6=Ytr_H0ht;?C5 z!Kr(%89Lfz*n2p2E0|FX8fCh(apl#`AnUv75feAq>+dPP3y`QJRSUQm#Mb9}6!UGB zdJvpp5*qQpi@ch?6VusbXoc7}skq4VUEZ;#)!4|eB`m#7Yp>}2{4m!1`CVUP%67b2 zRq2(PDa=FTY0E}VV$O{u)$?Vvr6-s@aU-MbCSP`lfvv)-g}Zt-KK4%}BGEq!WqF14 zX|J18KX6tgX+^&qrgHqGZdlr}ZyA^4^Uh4&h)vbMMZQB0Z0;yyPU+)KA&bJQ@iaA| z>QE%A{Fb3jU< zoI7HTtgraot1;llbR7NP$vfWsCpb%5++s~9NbB=_vBv9{I?3=}>jwjU*#u<`>^|O` zot8Rp$1PzN)Qx$M)m%enFM8ZLP?e2wg1Av__x!F4rW=#2z<-~3LY1C1?0?Y zOV#@(&WMsPU@k;?iWhh`WgZfIG!;*WKE)mndYLnZ`lXC31NF|};)U6)Fv>ezO22!7Ae0NqWYEEa&3}O$jg#z{xEV<%H6Cp| zXt~8VE&~?Y`hbG;3L~t_jqXj*V`Xh%G89rdX!AtfM2{ zKjb{+>1}%ivl5MWjAiOjKF68U_r-qj_2}i6e=YkQhWF+_JRpwQ;rbq1h3vJ)%Ltvi ziqx|jPE8g)tPhGFiqjJ*m+D#?wctCCH-WsEITc@#A?68Lgg6{bORU|gw91HFY0$Sre)XfpL7ZCV5*Dt& zWnbajVN&6X9rf8V9aICHb*;8NB@-lyR3CaJu_fI6=HNh)bNXZd3(*o90$wf#hQ|M3 zkMWq-)M^sQZs^y_iHd#z^u}&Udl>!{5PBLGC81@0i$m7ibllv5%d9!!`1Cb1;FefB z0@pxIV6$@t--Wvdw&4uL_GGu(0L>CU$RAUqa&52M?n2ACLyef53pmDG znF!+gl}h%g@9ZA`fhk?0WiGFL0c!S6YE9PL(616WKM@nsco-oa&S+s>zZ-Mn^ZPhl zF8JdCX;kyl^5cGR|+$f^a`3n`3pA?c2P9mAkhY zJs~cQU>@A#+V{2d$F|r8CcFQ^#6Rlk7AJ+{FF$CitLt<^%IJ+Ov{1^~-8`dZ+Npu3 z{HDGp>g;ZW`J%XR0;O`FX7y2y7h-SPOG9r~VzM{b<4l(M0@VcZurunqgt#JmQ;$X$ImqKo%1rAZ#}a6EB1z*Rz|Mwru~mj; zt|gmgC_6<(&Ds2bU$MDmAldnyEZP3$eg=z(=eAwt2(3a-l0jZ}layZJ&QrzS-e_?J z4!36({=gsaxqZ+mw2dqlCk?b*xF?a1W!UF@a^nY_K-cX9>iOI=^)+WV{-+2x1Jn=6 zwp~JhL8ADWB!Z^(<#hYx{9)kY}np<9FTNXW+3l zG@w-`$fa84^roMJJDQluP{Ve*jr8@&0(}7-Vz*e&5%8+=v`1RYq0qX2&=Hg5jcJ4+#z<*&e1F(oxe7OS%U5h zMOTN#emcqV=4lBD_()h?#)k`k86!Tj6Ah=5LhNBXjf#w~O^1?M%Z%ExuMS~q1_oK& zIyVminw5qljqdx}KsR4MAa$`%Rxpf&2(8@si30n&D-@e_{*N_5ybNeb1IA3&C$6CZ zbiF@Y{+f_bMO!bT=;J+ue7Yi9E><)2RVBn<)bW1J)Oy1Cn(m;nQFS3Wf&0osyDw znq}G@%$3cPzpf53WD~So{REJBcz6Kp7S!3<8O6DU|5iNmE!)2l9=APZ%YeK&3h87! zYglS(YP?kg!ttznQWf?-T>nR z|7+9Ri`_rAbMOBH)9F06z@cRat)XLm$i#XrSzN0O(|WM_(Lst4Qh$<%DF9&A@K4=1 z$45?Dbj*SG@s>IMZ@#E0i6kW|i4u3Qr-Ov%>N&82q$&M>q;XkJ);StgG#v>FdLGHM z6D@8_s~?TLnuL$dyn@)n5qD5v5vUa@Zl>E-ew@AtJ~m)Lh}P(>NOVbZ3Nti79Z}O@NLP^kK+L`0%Q!2^wczFVvjlcZLq6 zHQY$snXWjA^a?buF`kV~DOFVbE*W$k6X_#$Y!+8k#7Qv<5I{!3>i-R7w)L%zP$;zd z>GAF#)b1s=kfd3<7*N8yg#FL7sdd4^=8==Ev6k$h})e zo}^DJWRfcV0|VhtD+&E0Ba&0xF0QUBuR{(F4t^PRT~fM|g=J=vfn*0|1Z>hnEB2j< z%}q&P6!%L;sTWnYq%?bcV)?yj{LS7Tk3BuVIIQF zg;Xu|uAd|jzqb5TRgARsIh~g;Im6*1IuL0=tN!E#EfU8qIs6(BL*~U0SqBf_rIO=Z zijJCjUDKJKYFquGtoa>DLjK(~C&7G@;$LoqSKL|ZQAM}#qJmM$G7Nhh$B3_a@9;&g}ou%qnl;`=mBrCq;Y^Gh6nyyn3mr zYlzcYQyK>mmo!!h?xkq3FgFM5pv3oAD4KoV5hX8J&gY%tHr0a-5R~PW?4*Z+WK%8v zD8|5l{(hHUVoHQZ2D*P_*_a0tb$$N@a;k;T%Oo6(png%YeR>=DyppNGUZ}sOZtn#L ztv->#h}2^LOQrqNlwzJM-JD?(T@d<1`1&Sxi27uDUspwc@JO%)hu6|fbspoix<-w& z8hQx1P~xGQ4#W)I9_E>+mlC60h@KDynjv{PPcLa3`MU(2c1ZOgxLPVKCd(=@BidXC zTkyS{Y8SBpzN1$-aDq!haUvr5USUb@EdCW*YV`ORZ~l>I#ty2lC~o2l66#DK6jRn9 z&$Dm(=ySCbQ_^2;u)i@NpI}DTM^6^BdVVJYzNS~a;L%9>p{1!dUhyjDNQA*lC%KA+ zVCql$>oP%T{TXJM1Y=3)yZdQXsl3+YltYlI_G<`R)EKT|c4o^b@+=K*^}p^rc6l*& zu*R2WNu3@qKL(oCAI1ht$b5DK|K=Ij?dv*nGRMb2neY!#a^Nkv|C9(2HWA+{?)vSg zLeCB}1nkyLSahmUX!W}&16)~**sh=DhR9Mm0{4&-#cl#oXUPH$>&WEAbo|6iu8FPtE5@6YQ)h>)`{*@KhyKuFGJ-+je~(_$89y(*JQ?zXr1_L= z6f%&m!K~AGfI9f@-Lvn(wAarC7Ei`qv6k9!g&++oH+*M+#EFkHXn+Zy*w(Hkv# zAitc7wRG7Z;X7Mw%DG>66+d$_Z#3(eTfAIV(|>A$d0%(jL2K6K3C z)t}Xlpc(lKhGhi!V$VH+b+|caO-a(I>d-ro#HY>y)LYj{6k#pM4G0sJEaQ`Si zgpX-Jdg_bzw7O)aI#NMA9NA* z+Qxq0w)%8!*MZTT{+-1fqV5*PV{;I2|EL#58OR9li!#{*Pegsvc}AI={%+ZCQ<68? z0lw`n#^E!~*s6C+@b$x&$}Ru?{-9Cw^DCEyjlTs{VmbE^d+WIh@e(F5V*{#^H{e$(fD z+n!IMeD-kH(>|3HHm6K4jT|MhDRRc(sA3f$w8PI2_mFa^bRC zNw4;ie`90Ixj∾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 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_2a.png b/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_2a.png new file mode 100644 index 0000000000000000000000000000000000000000..e337f5c5635b1e457ff7c0f200b1d2203f0b6796 GIT binary patch literal 31501 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

    q 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

    @hyoEE#!ZN!J13lwr0XfQk2$8p<0e) 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 W3{~vwTlirR@YB}NQ?FLFkNO`EoWS}3 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_3b.png b/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_3b.png new file mode 100644 index 0000000000000000000000000000000000000000..80db03a93deb68d84d756011fd324eb52b6e7599 GIT binary patch literal 32730 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4a.png b/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4a.png new file mode 100644 index 0000000000000000000000000000000000000000..ad0d381042df54267d4749153d4e481112178db2 GIT binary patch literal 47916 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 C6%FM8 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4b.png b/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4b.png new file mode 100644 index 0000000000000000000000000000000000000000..1e4cd2f44d579290e4c795676037d524b4b38409 GIT binary patch literal 24813 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4c.png b/HelpSource/Classes/attachments/PbindFx/PbindFx_graph_4c.png new file mode 100644 index 0000000000000000000000000000000000000000..ac6e89f3f29a2d5c0512075c1cddb58024f203a8 GIT binary patch literal 33591 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 TRE}RI2>6kaRFtR@GYgeuYi#YHMO|1^39kJp+t z#cO@~06LjRmt9q_$ISF}gkAJc9tDRz^R8gP*)s?*8eBHvc8@I6XtB3_ERKXnR2hpd z6n8_BKtBzwKHpRBS2ve;mnEn~Wpm?o!Z$L{PZ8DE8St2&?6Qjk+8~l<- z!D0NF)6g1?9FKBvg@D$emoPftzeyDit0^|I{Iu9Klp#au3P@+11sX2Z{WnN%1Pyt# z$~@M{5;5{u9tDRwy@6*r)P#V*=td52yqBK0+2p}c6Oi>LO;&34hAMXzwYW==<7-5~ zrDBtpE;V9Se-h;-X#L^JZB1o+%`G%FB)C*;{${b6udc=1H@D*1g`Xfsxc*!QGYWE! z!5G>F5shSLxdf4HvAOIi^(nHhEjF{U2#nFu6pPDT;qh1_I;Tyg?-oV-9eM*Q;q0xXvD4ZxOt zyJ7HRyZp_nb=hfz#pda;VI!YbF#GoX42dGpxZ;j63ox$C(W|SF$il%9Dit zhtA<7ccIv9W^6y5j+rOV;+1{k`6Ns_c?nlpabMJ3lyPHlqu7LHjE`YVeHsT&UqW!pf#}FAP2%1{yNDoMJN`13u3m`lPi@BJsZSv7 z%LlP;Z)SNtywN_XPX2rnv%M#W{unU+WnfhbaPVtj{TyJ*X12H(je9)|1U?NMILNr> zRB|r?Wzn#N@%~?X?d39G@IR=SqGEtN#toPN^rJ%CLs{o3>yIB-uU~c&@Yrj>hn%Jk zev80hD#n)>hcX1t8--#~X8J*>W?u(}k7KllZ4~(UaS#?;?H^`*ld%W$)m?FD)Nrir zavc-5?Z#PcG^Y1xNpxCcYMW4)3bW94=TWrlm57WHi5Oja3~?LI;39Km|CWOlCyv9~ zdI$~;?u`>C_F?p?>prNv9iJO1bh8xo-dj-{BDmpK#qnjAsVu*@cc=kV7ou&`aG>cc z7;#`V4xBoN=2{M(j!W>s;33lX*QZ`A#QeXfN-_f5y^RSo+M`|bCNS!)h~}6&ejyh_ zV*BIHcI@*_;}8>W!Qua|M)T1r=-0U`+uQ?_9{vu?cJ4)Kd@KTPMB!Gw7uJd=!8z#l zCLn@);*ReGu7q%cQ6hiMN}x*u(3k~u?Zs0j;}tO6|2nYjBjEZ&+`ycH!u?Eo_ikYG zBwow{W(?;i!=ir!eWw5ysHkEp&9A{-fE62odwT%J0_Z#T1wJdHY!lQc_*_plpoxTK z+6pSlUjY@{=wUOZ`uOR|H)@xgxy6ReC?#yF01UfxAofL-p_wKC9ioDOkVZ%h)#1dC zoakcW@lKm?$=^0RE*={-1*Ln7(CtLH5VtQ`wFwFhNnTwyT21#Z4rn6Kkx2`TdRcz|k zz}yMIv!m=Sh}EC&5WL50 z9+g90DJQkSiWsE|+Wl|9@Z@1BPSRPu?x(B(6fC0kHsX2U)0s@`2+W@gbYl)FQ-z3I z>B=`gHWkM9>yC}v($MdmK(8@o^yr4?!fY@KP76#ha(rd{1jMy#1mW|RAm_NGN<*H- zhDHje1!yD-O-Kk1Xvp(LoHw>b7{|M>1AAQcAeL#~3PO}k#jS>t%wptmJOuTzn~w^l zA+N;DH=QaLr^lsphoNX;1t$&sQkd^}hRVt@q1(8$IkEalWOrJD8Iu#xD8Pn{kJ{r1 zWtZ2P*H(2H#8Bz>=q`-v+8ie8M9cM4xL6zvjmYb*#`(J(33CrBS&|PVz6fOfjcbie zXx6_4<5*f+`)Eb|Wf8D;CoQNpB#5NOzD1&mthE)Cul9oV^DogzzY0YQn1}HSLoRG> zsfbb^CDmpUl1JA~F7*@1u3XQ}b7A;T2QG1!0?op?Y-QPV#n*|7`7Mg>tP4k1-p@c9 zXRPP{#PTzN4wV$62hH`zM}4B$=#MT?L}K*=V_-6Jj9tmbxb)p<)?^GGbbw-|H69g7 zTDTe3YICf4EGA?#eJGWhFe>sD)^f#GSVF!Kh1Mzy;~YYK_)%#MP*JMWf$xn^q1p5I zZ$X~Hi2STo*mRj+T@?DB)|ZxP$(z39*ORO$%J~}WIX=3zX^oiPj{x7z!O2V4`I6xR zGPb?KoFP<5qJwij36Dacj$cI2T7zUU!&taGo8+JfC@s56keeYkjw`2)DY$M@Lu<=M z`hwB;?E4FLD^RlhJbytVRmPuBVz%|<$e~N%p1Xk@cH2Adg0Xi`wpLFaL!~4_Q}%S_ zRcQV>-F{!ld@Rp8^l=h94@D`oss^@};%uGbsgyng&d@g&Xo2FZY4oKnCwEors3@W` z73EtN}!Cj6ThjS6&%Zc2~CQKS@_Io?c2$vl9QXpaFj*EBSdP8~aqy>t(m z4Eb1f*{tu_Um7rx>~o`LOV`E>kZFf$sEq`TzYnm;wpwsb-ZN&XZNa%|_Ti(Hi zxOIsB!&qGVY9iJIq~NiUTQMMOILm#T85u%fz~nIlNQi*>HVK}#HFgXFCago*z|Iwb zE!{=yOp8XOq{tC(9RD0Guf;(BHB?>`ftGy{Orx$aYATfy6_ zc0^M#o`wFy1w6Qk3QY>_k&+NWA9;lp=Sc9$hvLQ`n(RnlR(Afq-Ywi(OiRiPbwFdN zoi?K72dsVdZ6wZHiwIL5tt=e^0|bZ_p{(RG{c8=Y#hc2Q->QNxs4;;v!(h}yt!c<> zn#5*3R1I{}HJDabk|)W~QMR+_iV{4#YSnlfPD3oC{Vxa}Cl4Czor+z%A{lB338Npu zITvy{DLl@qV9qx>LQPA~%ru=d-A&O2e1@(81XGr~tmYERrgbjzP&7(-uVvp5`AhhG z0n5_SNgYw4z z>e7hx6lD4Nas=cVqa2F*dQo{vSYO*v7xi|d*y@J?To-`Vt1@MatzOaPsz zX@$XBK4bS0Hek+)*)so#yzl~BFD9wlr&gO5dOPhE6vgM*~&u5*( z;+CyoY9RCIiX^q!jOTLvmq)>2X4kvW_V_U>H~Z#vSM9i+<4pYDiY#Ju<5;Y=k4=CS zMu)!mBMEspxb8B-QWHS>>pxUEYc2EWM8frFec(~%&^33?Sa%${)Lml0avP)^>Nx^3 zkM*2DR$u1u_i^a$&G^5s7V=Xv0x|+J0$xNwR%~7bQx+v7AS2)(2>cJhVSWKaZr5M{ O0000#Y<5kp$B?;dV0Di?^QKS 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 KMNUMnLSTZQbd${h literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/VarGui/player_4.png b/HelpSource/Classes/attachments/VarGui/player_4.png new file mode 100644 index 0000000000000000000000000000000000000000..eca189e433cfbf5c1093c3d2a7664e4cbfcb416d GIT binary patch literal 3893 zcmV-556bX~P)000jBNkl-LMM~VY*oW0hQ_E(XZ56HArnIYVx^1#+-0C)KHfwy= zCXEl;ZQ`azQ;Ln-Rzocc)`)^c>jPI@ZG9F*9s>@;u;;%p!rZyT+_~Ht?j6oa?#$eC z&-u@PzH{$4|9Ra%;BPxNcY+6w07rl$;714q`cYkYRX7410gixx04FwnBX9&b0)B@8 zCpN!pQeGjB07t+m1wrTads5M=#s!RybdcwZG93!^@I>$WE`RSW4{Pk(Rw~2;VG@^6T?~dYNICo^0y=GqWDHa$S|V`C zn2XxLEVKof+^P}U*@#428B(l82ymO4C-4;lDid2P&L2I9@{3J~8a*D_v!@{@Ox>yw zN&Gb78a8Ha0zwtaZUf#bTZu70jui+_p%hu!NZ$z&*N|o0%+yu3vZjqaGG&1)@MEX< z^(9g(8uu!S-hUj8&B_2aMYJJz`9$Q-?nLV0B3U?TB@vNYwJis&Ev>NG8r-Tyf38ho zIe>xHwc|^->3IU*AfU|Tk<`tG+Cv{>_qWZMmi-t;nTxS?-8Z;xl}xNSk}S22Ga0D` zF%caK50;l?kSuQpDr2T$3xYa3(ZP64$w7HZhA;FbORZ=}CL=ZF08?I)QOjiMEs&)~ zmb}$!WyEH4dr&$`Uu($HTUGs9UwIar^)5~w`U*wmH9+hXyzpEO9vSD@O|dneM`39_ z@>Z_Eq~XjcPhEk=s?9iAI}6XGI;QOpqC)r6{>=495R+jr82TeYR$kIKsKX|3u&fL& z5(UBL6Md=sd9SJe0F#VXll!imi|P(oG<83%)?Yj-p9rum;31Fl4BEu5xWv|s^W`PX zFscxs$;@4bxl`kT`ZM^?(FTk(-NOEo(?EO{@?Xe7VpQMHt_+K<6&3&5h@wj)u%w^> zFFn$MecS(uGYyX2s*a|+Ordl{nd~DCLop%&sJVGh{Wer;sfqKcubHGo#%oaHkQDBf zNHI`K&%L6Y*M)X63)$1d>q_}W0j{~Er0 z{dMtpbLAiKR6rRDHylEpo1t5`#Ady77R6V9yq9v26dQ~5$LHb+26E-aI}T6>1c$Km z^SIw`C$_GhVz|L=5e{->ohW_I#Q9_u*8fCGx}Q>c`mc#x31Xm>p35yyTj}InRusQIUb23W{Yv+?@jV~~}%7_lhBg&XaCR#HY+ zl)5Fro=t18rQU@?gSBO@!$;vTyx1o8BgJfb06WeZIwd7@zdtv={aM8`|LDkB%@^@OgozW?RzJlK;<^eZ?zo{gN{!tpad!4@2hwp-QMw(B!oZgTur zGseVWHcR*E!D>cnR$M=I7~eBlBcr@9^GMH~8i%N^-a1ude9aq%udDj9`CIna)c?bk ze67ceyP0y%wO%JJ=+_sQ+^*V+O@$R`Hbx*eAsO)*c8$sQ`Uc;hr3oDiF8xq~T1-Jo zY~TO#ZY?$#M`Hfc`B=YeC)R%5Ran~Gd}NIiuW=fN>^Jjpe(N5r>zdfW+$Dd)gs7e| zH@m9+{??g6LE~k53IY9|!_`x5opt41QD;n4iRp_=A{QgQqpiBvZm;Si3p{jb;miLcSVSCiW!R` z5io_x65p+^2VZ(4Hb>*ugNhDRQk?;;GEAJvO2$iTSEI3^nGJUt5n+k| zu}AyQY(PEcIjnkfDlCm=7{VhUhgRe>k1-e~Q*bX8UHmkL!4#$Pc7t9;(M@MGv$>MK zEzw>%q<)}%RfR8q(#mlzp$M2QMvf3j?htpkAq*@-T? zJe4-RTqYm*3$(}cjdLpzLfbqo$_~m)GDw!U1C?uk%*py?(b8-YY0vbht6PrdGhO5O9;0P#3fD@Z??08O& z07pQh2ykN4Xv1)|I0762tYaG}KZJ7I#qO`ro}TM#M?#%% zF}~_Zb(W&_c5~KP-56ittghCcOXC)s=a}&v-3ZXGihK9?9!Y*fXb%BSY}#uR-Dp%) zRD_#1?XPs!joMt%L4W`!wgGD7%a<>sqN2j#EfTbcmE!1{9zsn`4N_84^q{IHb-aDz zV{AEcU6Z=$T`A3svGoVY=H_OQV`6&Uj9$X2Q>Rc}U5$qye)z%Wcp|pq;$k5#DJjY8 zRk?NR78)8FB+H>!@gyfFyTr7%wifa6@eg#D6e5bGH)R-&esRl*YNqUzTNTQ1laovL zcNx8(zOb-RuzaRWnSzXr3`9n{e=CC=aQrv}dZd;4w=6!|jFeG#v3LJ5j9|`3=1q^r#e=(1eg&Ae zU>W95k7sWU0~)TJ#2351WUsJ>knY82G7%d_S6XrY=t04E=7@~hNNM;P;pr@zf`|S# zb^qXY)!J*Heu2-tdGkAd;IfVFH4gp9UVJ5g^hcVtf7d*AWpB z;gD$k`t^Oj)`^HMH#gTIPw$iV_I9C7jvYIOCie2mY15`*=FFMBlj!O<`M0d9IDo3O zr?7Ns9x9o$kx#0C?A%wdWX3go^7&4TN%$)!qY@i-6*HpC$MeYsoG#jdZR@OfXKgm> z4tr9oKm@=`=KoW^G?f9hm{q08T9u{n$R?tK!Lnj_fFeD@mOUW3H?9)Fvrmh;&5 z$xaxC{~1pvh+oaGD>%KbtnP`8x}Vf#qGSI2`8a#_tnfhX+qX|3wMmmE2_zR67w58D z<#m)bT0lq$`GSQ&YGPsw4|nZ^$37c6YSbvFn$fVp@#DvF;=~D|n>uUOEIj(?qX-T4 zhX*khujXYTj{R2#KU0p%|7PNesVNAwMKFg)-{HQc9k*-QoB7jTWY$}vV7<-$T|UmN zD@4tmU!kG29@$IY!}O#f47UWlQg;#u*o&1P_}g5`eD@AFFsE?Lckj2=g74muMw*;4 zvBU0fa~xVjbmm0E=`Qhpgzky0H$?RC&_hH=U0ofjs;WR^S#(fXy?Qkt0A_I~^a=(}OTYkD)A-h(08J_qz1ADdgZEt`P7mVslkV z9TJP<(l3~|-7F-J zioxUr;Om1YQBS@v>M!D8Nj<_Du_^PnIXDniTFYMlA4)|GY(AP5rFCC4c|hZ9Gz&*d zC201ICJ%ywy3G86)l%D~)3}&8xbg>aw4M4fgKcE39K% zwQALanOlp+f)76UKv>7t-(?YU^racm?c2B8RdV{4TJBL=S_;xLCnv`#y;KCX4=wj7 zD=X`BxrbO^DOqa7^|#&R>R@SZgqc}p;U*It-0-rlX>)U1w|`7ghskPj;k(!BFL5j3v>rd2##QcCRN$MVCElF@(Q!uT>0*m^0z4^oX6P_&^@tHMZ`-L?3L5<_tdFV zh4pqsAof7N7cN|gVZ(;mqrCo2%ajHe&R(0{DRoLh>zDq zOKq7VVxzGrtp-=iJhZAW*K6=1z=>_}w!OzSA3b_BXrVI?909E(z==)kEu20=#>#K*`+gV4wwVQJdc#IqbMDxvZvhXw<0geDiK-&m#V$*i}aP2q( z903IgaAH#c8qdNJ;0S0N0Zwe%ZXd24M}Q-s0D=DlZTj00000NkvXXu0mjf DWwC(c literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/VarGui/player_5.png b/HelpSource/Classes/attachments/VarGui/player_5.png new file mode 100644 index 0000000000000000000000000000000000000000..ceef9c521893a34d3fbaa4bee89d4c523cdd7875 GIT binary patch literal 3845 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 Hu0mjfmc~jx literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/VarGui/player_6.png b/HelpSource/Classes/attachments/VarGui/player_6.png new file mode 100644 index 0000000000000000000000000000000000000000..11ce114852243810b4805413e35837c289412d7e GIT binary patch literal 3991 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Classes/attachments/VarGui/player_7.png b/HelpSource/Classes/attachments/VarGui/player_7.png new file mode 100644 index 0000000000000000000000000000000000000000..d04c5cf6604b90daffb39ce2a6d1f59346c1244f GIT binary patch literal 3878 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 X)j@CB-@ldi00000NkvXXu0mjfNOEZc literal 0 HcmV?d00001 diff --git a/HelpSource/Guides/Guide_to_HS_and_HSpar.schelp b/HelpSource/Guides/Guide_to_HS_and_HSpar.schelp new file mode 100644 index 0000000..4fccb80 --- /dev/null +++ b/HelpSource/Guides/Guide_to_HS_and_HSpar.schelp @@ -0,0 +1,120 @@ + + + +TITLE::Guide to HS and HSpar +summary::objects for use of synth values in the language by event patterns +categories:: Libraries>miSCellaneous>HS and HSpar, Streams-Patterns-Events>HS and HSpar, OpenSoundControl, Server>Architecture +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/HS, Classes/PHS, Classes/PHSuse, Classes/HSpar, Classes/PHSpar, Classes/PHSparUse, Classes/PHSplayer, Classes/PHSparPlayer, Classes/PHSusePlayer, Tutorials/Event_patterns_and_LFOs, Tutorials/HS_with_VarGui + + +SECTION::Motivation + +Sometimes it may be desirable to use synth values in a Pbind (actually the derived EventStreamPlayer), I'm especially thinking of LFO-like controls for the generated synth(s). There are different ways to do this or something similar, see link::Tutorials/Event_patterns_and_LFOs:: for examples. + +As a general distinction for an event stream you can have new control values per event (1) or continuous control (2). +Some possible implementations: + +image::attachments/Guide_to_HS_and_HSpar/tab_2b.png:: + +There also exist elaborated language solutions that can be used in the above sense: see the interpolation methods in Wouter Snoei's wslib quark and (based on that) Splines with gui by crucialfelix. + +For (1) and (2) LFO behaviour can be defined using help synths (1c, 1d, 1e, 2a, 2b). If the Pbind-generated synths read values from control buses (1e, 2a, 2b), you don't have these values in the language (well, maybe you don't need them). With (1c) you have to use the internal server (of course this may also be ok). Having to define audio SynthDefs with respect to possible future control needs (1e, 2a) though is a bit unflexible. So (1d) integrates some nice features, nevertheless this has to be traded off with additional latency inherent in its mechanism: by using HS / PHS (and relates) help synth values are sent back to the client via OSCresponders, which works with local and internal server. + +The HS / PHS approach would especially be of interest if control behaviour could more easily be defined by server means than in SC lang (e.g. specific and / or nested UGens) but data should also be further manipulated in the language (e.g. for some kind of combinatorial use such as harmonic or polyphonic calculations). As a separate feature HSpar / PHSpar support timed and combinatorial possibilities to refer to more than one control synth (e.g. switching). This type of control, however, would not necessarily have to use the underlying demand-respond implementation. + +SECTION::Working scheme + +numberedList:: +## strong::Define help synth(s) by HS or HSpar.:: +These objects hold synth definitions, HS holds a single synth definition, +HSpar can hold more than one and has additional features. + + + +## strong::Define Pbind(s) by PHS (for HS) or PHSpar (for HSpar) to use synth values.:: + +## strong::Play PHS / PHSpar.:: +This instantiates a PHSplayer / PHSparPlayer object. Synth values are demanded and received for the use in defined Pbinds, HS / HSpar keep track of OSC traffic. PHSplayer / PHSparPlayer can be stopped and started with options, concerning Pbinds and help synths. + +Option, may be done immediately with (2) and (3) or later to "step in": + +## strong::Define further Pbind(s) by PHSuse / PHSparUse which refer to the same HS / HSpar.:: + +## strong::Play PHSuse / PHSparUse.:: +A PHSusePlayer object is instantiated, which can also be stopped and started with options. Different from PHSplayer / PHSparPlayer these options are only concerning the Pbind(s). Help synth control is defined by PHS / PHSpar or can be done by their players' methods strong::stop:: and strong::play::. Therefore steps (4) and (5) require the preceding definition resp. playing of PHS / PHSpar. Synchronization with other players can be done by the use of Quant objects. + +Instead of using PHSuse / PHSparUse objects in order to have separate players it's also possible to define several HS / HSpar objects independently. See link::Classes/PHSparUse:: for an example. + +A VarGui interface may be generated before step (3), see link::Tutorials/HS_with_VarGui::. +:: + +SECTION::Latency + +Due to the mechanism of demanding and receiving a synth value strong::before:: sending an actual message defined by the event pattern, there is a latency in addition to and independent from normal server latency (actually there are two, called strong::demandLatency:: and strong::respondLatency::). strong::demandLatency:: is the latency of the help synth(s) in relation to the synth value demands, driven by the Pbind duration pattern, respondLatency means the time given to the response to be received safely on time by the client. + +If these additional latencies are too small the communication between client and server may loose track of synth values needed by the event pattern and the mechanism breaks. On the other hand large latencies and heavy OSC traffic could need more CPU for bookkeeping - maybe you have to play around to find right values. Using the default latencies of HS / HSpar (demandLatency = 0.15, respondLatency = 0.15) and the Server (latency = 0.2) there is an overall latency of 0.5 sec (and in most cases you could lower this a lot if you need to). I didn't intend to use the whole thing for live performance, so just be aware. + + +subsection::OSC demand / respond mechanism to use server values in event streams + +Suppose HS defined, this happens when PHS is played: + +numberedList:: +## latency = 0 + +sequence of duration values generated in language +image::attachments/Guide_to_HS_and_HSpar/latencyCorr_1b.png:: + + +## latency = demandLatency + +(timing accuracy depends on defined time granulation) +in server: synth started, values taken at scheduled times +image::attachments/Guide_to_HS_and_HSpar/latencyCorr_2b.png:: + + + +## latency = demandLatency + respondLatency + +back in language, synth values can be used +e.g. to generate control data for an instrument +image::attachments/Guide_to_HS_and_HSpar/latencyCorr_3b.png:: + + +## latency = demandLatency + respondLatency + server latency + +if note event: (audio) synth started +image::attachments/Guide_to_HS_and_HSpar/latencyCorr_4b.png:: + +:: + + +SECTION::Relation to Pbinds and EventStreamPlayers + +PHS / PHSpar are almost "like" Pbind objects in the way, that event stream behaviour is defined. Internally two event patterns are defined, one for demand time and one for receive time. Consequently PHSplayer / PHSparPlayer also consist of more than one EventStreamPlayer (PHSparPlayer contains a third one for switching between help synths). This splitting seemed necessary for stopping and resuming Pbind(s) and help synth(s). + +You can easily sync PHSplayers / PHSparPlayers / PHSusePlayers themselves or with other EventStreamPlayers via Quant objects. The corresponding play methods take into account the needed time (caused by latency) to step into the quantization as early as possible. + + +SECTION::Granularity - internal quantization + +If several Pbinds are played in parallel, demands for values of the same help synth can be very close together, which causes possibly unnecessary OSC traffic: If accuracy of synth values is not very important (and for LFO-like purposes it is probably not) it seems sufficient to identify synth values from a small time region. This is done by the HS / HSpar parameter strong::granularity::, which defaults to 200, defining a time region of 0.005 seconds. Synth value demands within such a region are using just one (namely the first) demanded value, scheduling itself isn't affected. Mostly you won't have to think about this quantization - note that it has nothing to do with Quant objects and synchronizing players. + + +SECTION::Synth value access + +In the case of a single help synth (HS), values are accessible within the PHS / PHSuse by the local variable code::~val::, e.g. by code::Pkey(\val):: or a construction with code::Pfunc::. In the case of several help synths (HSpar), there is the option of defining a separately timed pattern to switch between playing help synths, always marking one as "current". Then code::~val:: refers to this current help synth, but reference behaviour can be differentiated by options and other keywords within the PHSpar / PHSparUse to get values of all playing help synths and other values (indices) which may be useful for control definitions. See examples in the help file link::Classes/PHSpar::, e.g. the last one. + + +SECTION::Order of execution + +If more than one Pbind is defined via PHS / PHSuse / PHSpar / PHSparUse the corresponding players will be started in order of definition with a small amount of time-shift between them, so that they can refer to each other (especially at coinciding points of logical time). See the last example of link::Classes/PHS::. + + +SECTION::About the examples + +Examples in the doc files use help synths values mainly for pitch - this seemes to make the concept quite clear. I preferred to take the default instrument to emphasize what is happening structurally. See link::Classes/HS:: examples for other usages. + +Be sure to have the right HS / HSpar definition evaluated before defining resp. playing a PHS / PHSpar ! - examples usually begin with a HS / HSpar definition and are thought to be worked through following the comments. + + diff --git a/HelpSource/Guides/Introduction_to_miSCellaneous.schelp b/HelpSource/Guides/Introduction_to_miSCellaneous.schelp new file mode 100755 index 0000000..20e71d4 --- /dev/null +++ b/HelpSource/Guides/Introduction_to_miSCellaneous.schelp @@ -0,0 +1,582 @@ +TITLE::Introduction to miSCellaneous +summary::overview, references and examples +categories:: Libraries>miSCellaneous, Guides +related:: Overviews/miSCellaneous + + +DESCRIPTION:: + +At the beginning of 2017, it was almost 10 years ago when I did my first steps in systematically ordering and extending personal SC tools. At that time I already had some experience in SC, but project-oriented composition was my main focus. Meanwhile miSCellaneous lib has grown and when I look at its readme file, although I always tried to keep stuff documented properly, I doubt that the connections between the different classes would be easy to get at a first glance. Topics accumulated, some help files have become huge (VarGui, PbindFx) and a lot of examples and documented (extra-)features might hide the basic motivations. As I was asked by colleagues at the Institute of Electronic Music and Acoustic Graz (IEM) we organized a one-day lecture/workshop on miSCellaneous lib on November 5th, 2016, and this tutorial summarizes the overview given then. At that point I'd like to say that I'm very grateful to IEM Graz and the interested SC community from here and abroad for support and feedback, we are going to have further SC meetings at the same place – Hanns Holger Rutz already continued in December. There's also a focus on artistic research here at IEM, and research projects, events and discussions are lighting an ongoing discourse in the field between art and science, creating an inspiring environment. + +Concerning the structure of this file: after a brief history and a grouping of content the tour will guide through selected topics in an order which, hopefully, will outline the central ideas. It will start with VarGui, PLx, then go over PbindFx, EventShortcuts to live coding aspects of PLx, continue with independent classes, class families, methods and SC tutorials and end with the Buffer Granulation tutorial, which again integrates some of the previous topics. PbindFx gets more space, as it's in my recent focus and you can use it for a number of things which are not, or at least not easily doable in plain SC. To a large extent the tour consists of references to selected already existing examples, which are spread over various help files. Conitinuative, but less central topics are marked as such, as well as some legacy code, which is still working, but not very relevant, as other possibilities have been invented meanwhile. A few new examples have been added, the reader is invited to check the exercises and to have fun with his/her favourite instrument resp. effect SynthDefs. + + + +SECTION::History + +In 2007 / 08 I was working at ZKM Karlsruhe, preparing a piece for flute and multichannel electronics (emphasis::Lokale Orbits / Solo 3::). Then I thought it would be useful to order and document my tools, by doing so my programming would – hopefully – not only be useful for me but for others too and I would be able to give something back to the open source community, from which I have been getting so much valuable input. Also I noticed that a better structuring of code together with the need of documentation stimulated reflection and development and significantly improved the functionality of my tools also just for personal use. + +emphasis::Lokale Orbits:: is a series of works for small instrumentations and multichannel tape where recordings with involved musicians were the base for granular processings. From the beginning miSCellaneous lib was developed in parallel to the needs that came from that artistic motivation. The first particular motivation was related to the fundamental architecture of SC – the division between language and server – and its consequences for granular synthesis. I never wanted to spend much time in gui programming, but I wanted to have a multi-purpose gui that would easily let me experiment with granular synthesis driven by language (patterns in particular) and server (granulation ugens). It should also be easy to combine these different controls in a single patch, e.g. fine-tune the parameters of a LFO and those of a Pattern resp. the derived running EventStreamPlayer at the same time. This need led to the development of the VarGui interface. It is the the oldest part and, so to speak, the kernel of miSCellaneous, already contained in the first public release of 2009. A player section and a number of features was added in 2011. Thus VarGui doesn't use SC's extended gui features which came up with the invention of Qt and if I had to build something from scratch I'd certainly look for a revised code structure, nevertheless VarGui reliably served my needs quite well over a long period of time. The twofold control option (environmental variables and synth args) turned out to be useful in many contexts, also the handling of arrays (environmental variables as well as synth args) is quite practical and allows a quick instantiation of huge slider+player guis. + +Between 2009 and 2016 a number of pattern families was added, some of them with granular synthesis in mind. The one I'm using most is the PLx proxy pattern family which takes advantage of environmental variables and dynamic scoping and goes well together with the VarGui interface concerning control of running Patterns/EventStreamPlayers. PLx also opens nice opportunities for live-coding with very condensed syntax. I'm not doing this on stage but I see live-coding as valuable part of a dynamic compositional process. As a side remark, PLx patterns mirror most of SC's main lib patterns and can also be used as non-proxies. In contrast to main lib's list patterns they default to repeats = inf, which probably saved myself the typing of many thousands of 'infs' over the years. + +Another part of miSCellaneous is a number of tutorials, which I added from time to time. Some refer to general SC topics, independent from miSCellaneous (e.g. Event patterns and array args), others to topics specific to miSCellaneous (e.g. PLx and live coding with Strings) and in some I tried a general overview of principal SC strategies, but also used examples with features of miSCellaneous (Buffer Granulation). Finally there's other stuff that doesn't fall into the above categories, e.g. the class EventShortcuts for customized shortcuts with Events and event patterns. Classes related to nonlinear dynamics (single sample feedback with Fb1, generailzed functional iteration synthesis with GFIS) have been added in 2018, Fb1_ODE and related, a framework for general ordinary differential equation integration of initial value problems in 2019. + +SECTION::Groups of content + +list:: + +## VarGui (2009), multi-purpose slider / player gui. Can have sliders for control of synth parameters and environmental variables as well as a player section for control of Synths, Tasks or EventStreamPlayers derived from Patterns. + +## Pattern classes/class families: + +list:: + +## PHSx (2009): pattern-like objects using synth values in language, still working but a bit outdated as we have synchronous buses now + +## PLx (2012): dynamic scope proxy patterns, especially suited for VarGui control, also live coding + +## PSx (2014): patterns acting like streams and remembering last values, good for certain types of nested pattern use and recursion + +## PmonoPar, PpolyPar (2015): differently timed setting of event streams + +## PbindFx (2015): sequencing arbitrary effects and effect graphs + +## PLbindef, PLbindefPar (2016): proxies based on Pbindef allowing shortcut replacement syntax + +## PSVx (2016): a pattern implementation of Xenakis sieves related to the class Sieve, Psieve patterns enable an unusual "realtime sieve modification". Interesting for many applications, e.g. granular rhythms, though I didn't have the time to experiment a lot yet. + +## PSPdiv (2017): a dynamic multi-layer pulse divider based on Pspawner + +## Other pattern classes +:: + +## Tutorials: + +list:: + +## Event patterns and Functions (2011) + +## Event patterns and LFOs (2011) + +## Buffer Granulation Tutorial (2012): different strategies of buffer granulation and control + +## Event patterns and array args (2015) + +## PLx and live coding with Strings (2016) + +## Sieves and Psieve patterns (2016) + +## kitchen studies (2016): commented source code of six short pieces from a kitchen sound using PbindFx + +## Live Granulation Tutorial (2017): different strategies of live granulation and control + +## Other tutorials +:: + + +## Other topics: + +list:: + +## enum (2013): general enumeration tool + +## EventShortcuts (2014): user-defined keywords for events and event patterns + +## Smooth Clipping and Folding (2017) + +## DX suite (2017): pseudo ugens for crossfaded mixing and fanning with drate control + +## Idev suite (2018): patterns and drate ugen searching for numbers with integer distance from a source pattern / signal + +## Fb1, GFIS (2018): single sample feedback and generalized functional iteration synthesis + +## Fb1_ODE (2019): general ordinary differential equation integration + +## ZeroXBufWr / ZeroXBufRd / TZeroXBufRd (2020): playing sequences of segments between zero crossings with demand rate control + +## Other +:: + +:: + +SECTION::Tour 1: VarGui + +The link::Classes/VarGui:: class help file as well link::Tutorials/VarGui_shortcut_builds:: are both bloated with information, so I'd like to give just a few examples and references here in order to show its basic features. + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +subsection::Tour 1a: synth control + +code:: +// quick control of default synth, specs are globally known +// note that amp is set to 0 by its default spec +// start by pressing the green button + +VarGui(synth: \default).gui + + +// alternative (shortcut build) writing + +\default.sVarGui.gui +:: + +For basic control of a self-defined Synth/SynthDef by passing control specs see link::Classes/VarGui#synth_0#this example:: in VarGui help. + +For control of multiple Synths/SynthDefs see link::Classes/VarGui#gt_0#this example:: in the same file below. + +It's often more practical to pass control specs as SynthDef metadata as done in link::Tutorials/Buffer_Granulation#1#Ex.1a:: of the Buffer Granulation tutorial. + + + +table:: + +## strong::Exercise::: Control your own (sustained) SynthDef with VarGui, either use SynthDef metadata or VarGui's argument 'synthCtr' for passing specs. + +:: + + +subsection::Tour 1b: environmental variables and pattern control + + +For basic control of an environmental variable in combination with a Pbind run link::Classes/VarGui#gt_1#this example:: in VarGui help. + +code:: +// after having evaluated p, consider the subtle differences of these variants: +// play with slider values and start and pause ad libitum. +// The quant argument ensures synchronization when starting players separately. + +// one array variable in one environment, one player +v = VarGui([\midi, [50, 70, \lin, 1, 55] ! 3], stream: p, quant: 0.2).gui; + +// three single variables in three environments, three players +v = VarGui([\midi, [50, 70, \lin, 1, 55]] ! 3, stream: p!3, quant: 0.2).gui; + +// three array variables in three environments, three players +v = VarGui([\midi, [50, 70, \lin, 1, 55] ! 3] ! 3, stream: p!3, quant: 0.2).gui; + +:: + +These examples show the application of dynamic scoping. A Function has been defined with an "unconnected" free variable and the players evaluate the Function in different Environments provided by the VarGui. Setting the sliders affects the variable of the same name in different Environments of different players. + +This example used a Pfunc, but it works the same with PLx patterns, we take a look at them and leave VarGui for a moment. + + + +SECTION::Tour 2: PLx suite + +Pdef and Pdefn are main lib's proxies for replacement of event patterns and non-event patterns. PL is the most general PLx proxy, taking over some combined functionality of Pdef and Pdefn on the base of dynamic scoping, go through the examples of the help file link::Classes/PL:: to see how it works with value and event patterns. + +Though what neither PL nor Pdef/Pdefn can provide is the replacement of pure lists or list items in the case of list patterns. There's a main lib workaround with a combination of Pn and Plazy (link::Tutorials/PLx_suite#Ex. 1a#PLx suite, Ex.1a::), but it isn't satisfying for several reasons, so I suppose that PLx list patterns like PLseq are amongst the most useful ones of the whole PLx family, e.g. see link::Tutorials/PLx_suite#Ex. 1b#PLx suite, Ex.1b::. Other PLx list patterns like PLrand, PLwrand, PLser, PLshuf, PLshufn, PLswitch etc. work similar. + +There exists also a number of non-list PLx patterns, have a look at link::Classes/PLwhite:: as a typical example. + + +table:: + +## strong::Exercise::: Play your own enveloped SynthDef (or take default SynthDef with params: freq, amp, pan) with some PLx patterns and perform live replacements as in the examples above. +:: + + + +SECTION::Tour 3: PLx patterns used with VarGui + +See link::Classes/VarGui#Ex. 1a#VarGui, Ex.1a::, for basic step sequencing with PLseq, the array variable is implicitely defined in VarGui's first arg. + +See link::Classes/VarGui#Ex. 1c#VarGui, Ex.1c::, for multiple players and array variables and control of multiple sliders and buttons with modifier keys (note that not all functionality might be available on all platforms). + +See link::Classes/VarGui#Ex. 4a#VarGui, Ex.4a::, for a sequencing setup with some PLs used. But more interesting here is that each synth reads is base frequency from a control bus, which gets its data from a separate synth. Synth and EventStreamPlayer are both controlled from the gui. The two slider blocks on the left side concern Synth settings (above) and variable setting for the Pbind / EventStreamPlayer (below). Accordingly we have two players on the right side. Try running the player and starting and stopping the control synth. + +link::Tutorials/Buffer_Granulation#2#Buffer Granulation, Ex.2a::, shows basic language-driven granulation, gui values are taken over by PL patterns and Pfunc. + + +table:: + +## strong::Exercise::: Write a combination of an event pattern and PLx patterns as above with your own SynthDef and play it with a VarGui. Note that it's not necessary to control all args by the gui, nor is it necessary to control parameters directly: you can e.g. control bounds for midinotes in the gui and define the calculation for the actual midinote (e.g. random selection) in the event pattern: + +code:: +\midinote, PLwhite(\midiLo, \midiHi), +:: + +:: + + +SECTION::Tour 4: PbindFx + +PbindFx is an event pattern for effect handling on per-event base. There are other ways for working with event patterns and effects, already possible with main lib, but they have disadvantages: with Pfx and Pfxb there is no built-in way to sequence effect types or effect parameters, you could also route the event's audio to effect buses, but for overlapping events with different fx graphs/params you'd have to define additional buses beforehand as in Ex. 4a. + + +subsection::Ex. 4a: sequencing fx params by using different fx buses + +First go to link::Classes/PbindFx#Ex. 1a#PbindFx, Ex. 1a::, reboot server with extended ressources and evaluate source and fx synths. + + +code:: +// start fxs +( +a = Bus.audio(s, 2); +b = Bus.audio(s, 2); + +x = Synth(\echo, [decayTime: 1.5, echoDelta: 0.15, in: a]); +y = Synth(\echo, [decayTime: 5, echoDelta: 0.1, in: b]); +) + +// play pattern, the two effects allow switching between them +( +p = Pbind( + \dur, 0.5, + \instrument, \source, + \note, Pshuf((0..11), inf) + Pseq([[0.2, 14.2], [0, 4], [0, 4]], inf), + \octave, Pwhite(3, 6), + \out, Pseq([b, a, a], inf) // here we do fx sequencing +).play +) + +p.stop + +// we need to do cleanup manually here + +[x, y, a, b].do(_.free); + +:: + +subsection::Ex. 4b: sequencing fx params by using PbindFx + +code:: +// Ex. 4a translated to PbindFx syntax – +// though it's not exactly identical as fxs are processed in not only two but +// more parallel fx synths + +( +p = PbindFx([ + \dur, 0.5, + \instrument, \source, + \note, PLshuf((0..11)) + PLseq([[0.2, 14.2], [0, 4], [0, 4]]), + \octave, Pwhite(3, 6), + \fxOrder, 1 // always fx #1 (echo) + ],[ + \fx, \echo, + \decayTime, PLseq([5, 1.5, 1.5]), + \echoDelta, PLseq([0.1, 0.15, 0.15]), + \cleanupDelay, 5.2, // with short default echo would be cut + + // this would save a bit CPU + // \cleanupDelay, PLseq([5, 1.5, 1.5]) + 0.2 + ] +).play +) + + +// cleanup (delayed freeing of synths and buses) is done automatically +// watch server window: + +p.stop + + +// now run the same example with the following variant of 'echoDelta', +// obviously the result cannot be achieved with an approach like in Ex. 4a + + \echoDelta, Pwhite(0.05, 0.2) +:: + + +subsection::Ex. 4c: alternation of fx / non-fx by defining a fxOrder sequence + +code:: +( +p = PbindFx([ + \dur, 0.2, + \instrument, \source, + \note, PLshuf((0..11)) + PLseq([[0.4, 14.4], [0, 4], [0, 4]]), + \octave, Pwhite(3, 6), + + // fxOrder = 0 means no fx + \fxOrder, PLseq([0, 0, 1]), + + // if no fx, we need to compensate the unified echo delay of 0.2 + \lag, Pif(Pkey(\fxOrder) > 0, 0, 0.2) + ],[ + \fx, \echo, + \decayTime, PLseq([5, 1.5, 1.5]), + \echoDelta, Pwhite(0.04, 0.12), + \cleanupDelay, PLseq([5, 1.5, 1.5]) + 0.2 + ] +).play +) + +p.stop + +:: + + +table:: +##strong::Exercise::: Play your own (percussive + stereo) SynthDef (or instrument 'source') with an arbitrary sequencing of no fx and echos (by defining 'fxOrder') and echo params as in Ex. 4c. Note that in fx 'echo' the max echoDelta defaults to 0.2. +:: + +subsection::Tour 4d: principles of operation + +For each event several issues have to be internally considered by PbindFx: building and checking of fx graphs (no cycles !), cleaning buses from possibly remaining residual audio (adding "zero synths"), splitting (in case of parallel parts in the fx graph), grouping of all event-related synths and checking accumulated cleanup delay times. You might skip that for the moment, but for a more detailled overview see link::Classes/PbindFx#Principle of operation#Principle of operation::, as well as for a listing of conventions. + + +subsection::Tour 4e: sequential application of fxs (fixed fx chains) + +See PbindFx, examples link::Classes/PbindFx#Ex. 1a#1a:: and link::Classes/PbindFx#Ex. 1b#1b::. + + +subsection::Tour 4f: sequencing different fx chains + +See PbindFx, examples link::Classes/PbindFx#Ex. 2a#2a::, link::Classes/PbindFx#Ex. 2b#2b::, link::Classes/PbindFx#Ex. 2c#2c::, link::Classes/PbindFx#Ex. 2d#2d::. + +table:: +##strong::Exercise::: Play your own (percussive + stereo) SynthDef (or instrument 'source') with an arbitrary sequencing of fx chains (your fxs and/or fxs from PbindFx help). Maybe just extend your last own example. +:: + +subsection::Tour 4g: parallel effects and arbitrary effect graphs + +It seems to be a still underestimated option to design effect graphs different from simple chains. In a classical DAW interface a pile of slots for effects in chain is common, although more differentiated possibilities are also there. Considering event sequencing with PbindFx we can select fx graphs per event / grain, in addition to the sequencing of fx parameters itself. See link::Classes/PbindFx#Ex. 10a#PbindFx, Ex.10a::, for a parallel application of echo, note the syntax of the event graph, passed as Event to 'fxOrder'. + +table:: +##strong::Exercise::: Compare the sound of the two fx graphs given in link::Classes/PbindFx#Ex. 10a#Ex.10a::, also try the following or similar, how do the corresponding fx graphs look like ? + +code:: + \fxOrder, `(0: 1, 1: [2, 3], 2: 4), + + \fxOrder, `(0: 1, 1: [2, 3, \o], 2: 4), + + \fxOrder, `(0: 1, 1: [2, 3], 3: 4, 2: 3), + + \fxOrder, `(0: 1, 1: [2, 3], 3: 2, 2: 4), + + \fxOrder, `(0: 1, 1: [2, 3, \o], 3: 4, 2: 3), +:: +:: + +See PbindFx, Ex. link::Classes/PbindFx#Ex. 10b#10b:: and link::Classes/PbindFx#Ex. 10c#10c:: for modulation graphs and their sequencing. + +table:: +##strong::Exercise::: Play your own (percussive + stereo) SynthDef (or instrument 'source') with an arbitrary sequencing of fx *graphs* (your fxs and/or fxs from PbindFx help). Maybe just extend your last own example. +:: + +subsection::Tour 4h: implicit parallelism of single effects + +This can simple be done by passing arrays within fxData, see link::Classes/PbindFx#Ex. 4#PbindFx, Ex.4a::. + + + +subsection::Tour 4i: different effects with parallel PbindFxs + +A further option for parallelism, a typical case would be the application of different effects to the notes of a chord, see link::Classes/PbindFx#Ex. 3b#PbindFx, Ex.3b:: (rather straight than 3a). + + +subsection::Tour 4j: PbindFx and replacements + +See link::Classes/PbindFx#Ex. 7a#PbindFx, Ex.7a:: for replacement of key streams. + +Up to now PbindFx got lists as args in all examples. As args can be event patterns too, they can also be proxy patterns which opens the door for various unusual kinds of source and fx replacements, see PbindFx Ex. link::Classes/PbindFx#Ex. 7b#7b:: and link::Classes/PbindFx#Ex. 7c#7c::. + +table:: +##strong::Exercise::: Take one of your previous working PbindFx examples and rewrite its args (arrays of key/value pairs) as PL or Pbindef proxies. Run the example and replace source and/or fx patterns on the fly. +:: + + +subsection::Tour 4k: continuative topics + +For use with VarGui see link::Classes/PbindFx#Ex. 8#PbindFx, Ex.8::. + +For using one fx SynthDef in more than one fxData see link::Classes/PbindFx#Ex. 4#PbindFx, Ex.4::. + +For source and fxs reading from external buses (ar or kr) see link::Classes/PbindFx#Ex. 6a#PbindFx, Ex.6a-c::. + +For using value conversions with fxData see PbindFx, link::Classes/PbindFx#Ex. 9#PbindFx, Ex.9::. + + +subsection::Tour 4l: kitchen studies, a granular synthesis application + +One motivation for the development of PbindFx was the idea to explore granular synthesis variants with differentiated effect processings. The fixed media composition emphasis::kitchen studies:: collects six short pieces with different fxs and handlings of fx sequencing, each derived from the kitchen sound of five seconds, which is already contained in miSCellaneous lib. At the same time emphasis::kitchen studies:: is an ongoing artistic research project: the commented source code is published in the tutorial link::Tutorials/kitchen_studies::, compressed versions of the original piece as a whole and its parts can be found on my website link::http://daniel-mayer.at:: (use a separate browser, players won't work within this window), a further documentation of the compositional process will follow as publication in the artistic research database emphasis::Research Catalogue:: (link::http://researchcatalogue.net::). + + +SECTION::Tour 5: EventShortcuts: less typing with Events and event patterns + +EventShortcuts is an interface for defining your own shortcut keys for often used keyword in Events and event patterns. For example you might want to write 'inst' or just 'i' instead of 'instrument' etc., then define your collection of shortcuts – e.g. in your startup or a certain load file – and activate it on occasion. There is also a default shortcuts dictionary, see its content and play a simple example: + +code:: + +EventShortcuts.on; + +EventShortcuts.postAll; + +x = Pbind(\m, Pwhite(60, 90), \d, 0.2).play; + +:: + +For examples of (re-)defining or extending shortcut dictionaries see link::Classes/EventShortcuts::. + +table:: +##strong::Exercise::: Take one of your favourite SynthDefs with non-standard arguments (other than freq, amp, pan, etc.) and write an event pattern example, using these arguments. Then choose useful abbreviations, define a new shortcut dictionary with these (either by extending the default or by defining a new one), make it current and run the event pattern example with abbreviated keys. +:: + + +SECTION::Tour 6: live coding + +This was not my main focus from the beginning, but it turned out that PLx patterns, in combination with EventShortcuts and/or Character sequencing (tour 6b) open up live coding possibilities with very condensed syntax. + + +subsection::Tour 6a: PLbindef and PLbindefPar + +PLbindef is a wrapper class for Pbindef, which allows replacements in pseudo-method syntax in a newly created Environment. + +code:: +EventShortcuts.on; + +PLbindef(\x, \d, 0.2, \m, Pwhite(60, 90)).play; + +// Now 'x' is also the name of a new PLbindefEnvironment in the current Environment, +// its pseudo-methods can be used for setting, moreover it is a player also. + +~x.play + +~x.m = PLseq((60..70)) + +~x.stop + +:: + +For further examples see link::Classes/PLbindef::. + +PLbindefPar is also based on Pbindef, but unlike PLbindef it's not a plain wrapper: it employs a number of Pbindefs in parallel, which allows control of polyphonic, additive or granular structures, see link::Classes/PLbindefPar::. + +warning:: +If you're piling up a lot of layers, be careful with amplitudes, the amplitude values are taken for the single layers, so you'd have to reduce them accordingly ! +:: + +subsection::Tour 6b: PLx and live coding with Strings + +Already in plain SC Strings as Arrays of Characters can be used for sequencing. PLx patterns fit and continuate this concept, see link::Tutorials/PLx_and_live_coding_with_Strings:: for some options, also in connection with PLbindef, PLbindefPar and PbindFx. + + +SECTION::Tour 7: independent classes, class families and methods + +subsection::Tour 7a: PSx stream patterns + +These are a bit paradoxical classes: Patterns which behave as if they were Streams, thus have an internal state and remember its last value(s), which can e.g. be used for recursion or certain demands of repeated embedding as in the following example: + +code:: + +( +// PS gets source and length patterns as args + +p = PLseq([ + PS(PLseq((1..5)), PLseq([1, 2])), + PS(PLseq((1..5) * 100), PLrand((3..5))) +]); + +p.asStream.nextN(100) +) + +// this can also be written with a combination of Streams and Patterns, +// but it needs more typing (same with Pswitch1 variants) + +( +a = Pseq((1..5), inf).asStream; +b = Pseq((1..5) * 100, inf).asStream; + +p = Pseq([ + Pfuncn({ a.next }, Pseq([1, 2], inf).asStream), + Pfuncn({ b.next }, Prand((3..5), inf).asStream), +], inf); + +p.asStream.nextN(100) +) +:: + +See link::Tutorials/PSx_stream_patterns:: for an overview. + + +subsection::Tour 7b: PSVx sieve patterns and Sieves + +Sieves, recommended by Iannis Xenakis as generative principles for arbitrary musical parameters, are implemented twice: with the class Sieve and Psieve patterns, which adapt the sieve calculus for realtime interactions. The tutorial link::Tutorials/Sieves_and_Psieve_patterns:: starts from scratch, thus can be studied completely independent from other miSCellaneous stuff and most other SC requirements. The last chapter gives some audio examples, granular rhythms might be an especially interesting application. + + +subsection::Tour 7c: PmonoPar and PpolyPar + +link::Classes/PmonoPar:: follows the Pmono convention of a single synth, being set but extends it to an arbitrary number of differently timed setting streams. With link::Classes/PpolyPar:: the number of continously running synths is arbitrary as well and setting streams can switch the synths to set. That way complicated fx variations can be achieved by a paradigm different from link::Classes/PbindFx::. + + +subsection::Tour 7d: enum + +A general tool, which can be used for many enumeration and optimization problems (sets, partitions, graphs etc.), melodic shapes and scales are possible musical applications, see link::Tutorials/enum::. + + +subsection::Tour 7e: HS / HSpar / PHS / PHSpar + +A framework for using server-generated values in Pbind-like objects in the language. A bit outdated now, as synchronous bus gives easy access to server values, however the double-latency mechanism provides a good accuracy of values – if this is needed – by passing a high granularity parameter. A lower value minimizes OSC traffic if this is more important. See link::Guides/Guide_to_HS_and_HSpar::. + + +subsection::Tour 7f: PSPdiv + +A dynamic multi-layer pulse divider based on Pspawner, as the latter it supports parallel and sequential sprouting of sub-patterns. Might be used for line ornamentation, polyrhythmical structures, granulation etc., see link::Classes/PSPdiv::. + + +subsection::Tour 7g: Smooth Clipping and Folding + +A suite of pseudo ugens, see link::Tutorials/Smooth_Clipping_and_Folding::. + + +subsection::Tour 7h: DX suite + +pseudo ugens for crossfaded mixing and fanning according to demand-rate control, see link::Tutorials/DX_suite::. + + +subsection::Tour 7i: Idev suite + +patterns and drate ugen searching for numbers with integer distance from a source pattern / signal, see link::Tutorials/Idev_suite::. + + +subsection::Tour 7j: Nonlinear dynamics + +pseudo ugens for single sample feedback and generalized functional iteration synthesis, see link::Classes/Fb1:: and link::Classes/GFIS::. General ordinary differential equation integration, see link::Classes/Fb1_ODE:: and related classes. + +subsection::Tour 7k: ZeroXBufWr / ZeroXBufRd / TZeroXBufRd + +pseudo ugens for zero crossing analysis and playing sequences of segments between them with demand rate control, see link::Classes/ZeroXBufWr::, link::Classes/ZeroXBufRd::, link::Classes/TZeroXBufRd::. + + + + + +SECTION::Tour 8: (Rather) independent SC tutorials + + +subsection::Tour 8a: Event patterns and Functions + +This tutorial is about dynamic scope, comparing the behaviour of Functions, Streams and EventStreamPlayers in Environments. It's thus treating some preconditions which are relevant for link::Tutorials/PLx_suite:: and link::Classes/VarGui::, see link::Tutorials/Event_patterns_and_Functions::. + + +subsection::Tour 8b: Event patterns and LFOs + +Continuous (with LFO) and discrete ("LFO-like") control strategies for event patterns are compared in link::Tutorials/Event_patterns_and_LFOs::. + + +subsection::Tour 8c: Event patterns and array args + +SynthDef array args seem to be a sometimes confusing topic, especially when it's about (pseudo-)variable array lengths and Envelopes, this is even more the case when it comes to the sequencing of such synths. For this reason, and not at last to remind myself to the subtle syntax differences, I wrote this tutorial: link::Tutorials/Event_patterns_and_array_args::. + + +SECTION::Tour 9: Buffer Granulation and Live Granulation – tutorials + +Actually scheduled as a general overview of granulation possibilities in SC, also collecting various ideas from the sc-users mailing list discussions, I have to admit that in its current form many examples, especially in the Buffer granulation tutorial, require one or more features of miSCellaneous and thus might not always be easy to follow. Then again it would be hard to write such (gui) examples without presuppositions and at the same time with a clearly representable amount of code. However I hope that based on this guided tour it might be easier to step through for people who haven't used this lib before, see link::Tutorials/Buffer_Granulation:: and link::Tutorials/Live_Granulation::. + + + + + + + + diff --git a/HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_1b.png b/HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_1b.png new file mode 100644 index 0000000000000000000000000000000000000000..8a9d6b4d774c91ae68c926e9b60d0d6393fbbcea GIT binary patch literal 2838 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 F{ukdSYexV8 literal 0 HcmV?d00001 diff --git a/HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_4b.png b/HelpSource/Guides/attachments/Guide_to_HS_and_HSpar/latencyCorr_4b.png new file mode 100644 index 0000000000000000000000000000000000000000..f205c45004c4183fb1a6c5e0432276bc93795e51 GIT binary patch literal 4942 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 z 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Overviews/miSCellaneous.schelp b/HelpSource/Overviews/miSCellaneous.schelp new file mode 100644 index 0000000..c70a857 --- /dev/null +++ b/HelpSource/Overviews/miSCellaneous.schelp @@ -0,0 +1,494 @@ +TITLE::miSCellaneous +summary::a library of SuperCollider extensions (c) 2009-2020 Daniel Mayer +categories:: Libraries>miSCellaneous +related:: Guides/Introduction_to_miSCellaneous + +DESCRIPTION:: + +Version 0.23 contains these class and help files (SCDoc and old HTML system): + +numberedList:: + +## link::Guides/Introduction_to_miSCellaneous::: recommended starting point. + +## link::Classes/VarGui:: : a slider / player gui to set envir variables and synth controllers and play synths, event patterns and tasks, see also link::Tutorials/VarGui_shortcut_builds::. link::Tutorials/HS_with_VarGui::, a specific tutorial about the combination of HS family and VarGui. + + +## General tutorials: link::Tutorials/Event_patterns_and_LFOs:: contains an overview of related LFO-control setups with event patterns. +link::Tutorials/Event_patterns_and_Functions:: is treating requirements of the control of EventStreamPlayers with VarGui. link::Tutorials/Event_patterns_and_array_args:: focusses on passing arrays to synths with patterns. +link::Tutorials/enum:: is a general enumeration method suited for many combinatorial problems such as listing subsets, partitions of integers, +searching for paths within graphs etc. + +## link::Tutorials/PLx_suite::, dynamic scope variants of common Pattern classes for convenient replacement. Can be used for shorter writing of Pbinds to be played with link::Classes/VarGui:: and / or live coding, see link::Tutorials/PLx_and_live_coding_with_Strings::. link::Classes/PLbindef:: and link::Classes/PLbindefPar:: as subclasses of link::Classes/Pdef:: allow replacement of key streams in shortcut pseudomethod syntax. + +## link::Tutorials/PSx_stream_patterns::, Pattern variants that have a state and can remember their last values. Can be used for recording streams and event streams (link::Classes/PS::), data sharing between event streams (link::Classes/PSdup::), comfortable defining of subpatterns with counted embedding, defining of recursive (event) sequences (link::Classes/PSrecur::) and building loops on given Patterns/Streams with a variety of options, also for live interaction (link::Classes/PSloop::). + +## Event pattern classes for use with effects: link::Classes/PbindFx:: can handle arbitrary effect graphs per event, link::Classes/PmonoPar:: and link::Classes/PpolyPar:: follow the Pmono paradigm. The tutorial link::Tutorials/kitchen_studies:: contains the documented source code of a fixed media piece using PbindFx for granulation. + +## Further Pattern classes: link::Classes/PlaceAll::, link::Classes/Pshufn::, link::Classes/PsymNilSafe::. link::Classes/PSPdiv:: is a dynamic multi-layer pulse divider based on Pspawner. + +## link::Tutorials/Buffer_Granulation::, a tutorial covering different approaches of implementing this synthesis method in SC (server versus language control, mixed forms), examples with link::Classes/VarGui::, language-driven control with link::Tutorials/PLx_suite:: patterns. The tutorial link::Tutorials/Live_Granulation:: summarizes direct options without explicit use of a buffer. + +## A family of classes for the use of synth values in Pbind-like objects. +Take link::Guides/Guide_to_HS_and_HSpar:: as a starting point, see also link::Classes/HS::, link::Classes/PHS::, +link::Classes/PHSuse::, link::Classes/HSpar::, link::Classes/PHSpar::, link::Classes/PHSparUse::, +link::Classes/PHSplayer::, link::Classes/PHSparPlayer::, link::Classes/PHSusePlayer:: + +## link::Classes/EventShortcuts::, a class for user-defined keywords for events and event patterns. The tutorial link::Tutorials/Other_event_and_pattern_shortcuts:: collects some further abbreviations, e.g. functional reference within events and event patterns, similar to Pkey. + +## An implementation of Xenakis' Sieves as class and pattern family, see link::Tutorials/Sieves_and_Psieve_patterns:: for an overview and examples. + +## FFT pseudo ugens for defining ranges by bin index: link::Classes/PV_BinRange:: and link::Classes/PV_BinGap::. + +## link::Tutorials/Smooth_Clipping_and_Folding::, a suite of pseudo ugens. + +## link::Tutorials/DX_suite::, pseudo ugens for crossfaded mixing and fanning according to demand-rate control. + +## link::Tutorials/Idev_suite::, patterns and drate ugen searching for numbers with integer distance from a source pattern / signal. + +## Nonlinear dynamics: link::Classes/Fb1:: for single sample feedback / feedforward and link::Classes/GFIS:: for generalized functional iteration synthesis. link::Classes/Fb1_ODE:: for ordinary differential equation integration. + +## link::Classes/ZeroXBufWr::, link::Classes/ZeroXBufRd::, link::Classes/TZeroXBufRd::, pseudo ugens for analysis of zero crossings and playing sequences of segments between them with demand rate control. +:: + + + +Many of the examples here are using patterns, resp. event patterns but do not cover their basic concepts. +For a detailled description of SC's sequencing capabilities see James Harkins' Practical Guide to Patterns +(link::Tutorials/A-Practical-Guide/PG_01_Introduction::), the tutorial link::Tutorials/Streams-Patterns-Events1::, and the Pattern help files +(link::Classes/Pattern::, link::Classes/Pbind:: and the type-specific ones). + +VarGui handles namespace separation by using different Environments. +So a gui for control of parametrized families of different types of objects can be built on the fly +(e.g. a number of EventStreamPlayers from a single Pbind definition with snippets of functional code, +a number of Function plots from a single parametric function definition etc.). +See link::Classes/Environment:: and link::Classes/Event:: helpfiles for the underlying concepts and +link::Tutorials/Event_patterns_and_Functions:: and link::Tutorials/PLx_suite:: +for their application to Event patterns resp. EventStreamPlayers. + + + +SECTION::Requirements + +At least SuperCollider version 3.6 but newer versions are recommended, +with 3.6 you'd have to use Qt GUI kit, which is the only option anyway from 3.7 onwards. +Unable to test on 3.5 anymore, code might work, anyway old help is still supported. + +If you still use Cocoa or SwingOSC with these old SC versions, +you can take miSCellaneous 0.15b and add classes and help files from a +newer version of miSCellaneous. + +For using VarGui with EZSmoothSlider and EZRoundSlider you would need to +install Wouter Snoei's wslib Quark, one buffer granulation +example using Wavesets depends on Alberto de Campo's Wavesets Quark. + +I tested examples on SC versions 3.6 - 3.11, +on OS 10.8 - 10.13, Ubuntu 12.04 and Windows 7, 10; +though not every platform / OS version / SC version combination. + + +SECTION::SCDoc issues (SC 3.10) + +With SC 3.10.0 - SC 3.10.2 there are issues with evaluating code in the +help file examples (double evaluation). +For these versions you'd rather copy the help file code into scd files and run it there. +Double evaluation has been fixed with 3.10.3 (August 2019). +With SC updates to 3.10 it might happen that help file examples are invisible. +In that case delete the Help folder which resides in one of these places, depending +where you have installed: + +code:: +Platform.userAppSupportDir; +Platform.systemAppSupportDir; +:: + +Then restart SC. + + +SECTION::Installation + +By version 0.17 you can install either via the quarks extension management system or a +downloaded zip from GitHub or my website. Both methods shouldn't be combined, +e.g. if you have already done a manual install +before by placing a miSCellaneous folder in the Extensions folder, then remove +it from there before the quarks install. + + +SUBSECTION::1.) Installation via Quarks + +This requires a SC version >= 3.7, see the recommended ways to install here: + +link::http://doc.sccode.org/Guides/UsingQuarks.html:: + +link::https://github.com/supercollider-quarks/quarks:: + +After a install of a newer version of miSCellaneous do a SCDoc update by + +code:: +SCDoc.indexAllDocuments(true) +:: + + +SUBSECTION::2.) Manual installation from a downloaded zip + +You can download the newest version from + +link::https://github.com/dkmayer/miSCellaneous_lib:: + +and the newest and all previous versions from here: + +link::http://daniel-mayer.at:: + +Copy the miSCellaneous folder into the Extensions folder and recompile the class library +or (re-)start SC. If the Extensions folder doesn't exist you'd probably have to create it yourself. +Check SC help for platform-specific conventions (or changes) of extension places. + +list:: +## Typical user-specific extension directories: + +list:: +## OSX: ~/Library/Application Support/SuperCollider/Extensions/ +## Linux: ~/.local/share/SuperCollider/Extensions/ +:: + +## Typical system-wide extension directories: + +list:: +## OSX: /Library/Application Support/SuperCollider/Extensions/ +## Linux: /usr/share/SuperCollider/Extensions/ +:: + +:: + +You can check Extension directories with + +code:: +Platform.userExtensionDir; +Platform.systemExtensionDir; +:: + +On Windows see the README file of SC for the recommended extensions path. +On Windows and OSX you might have to make the concerned folders visible, +if they aren't already. The miSCellaneous folder should be placed directly +into the Extensions folder, not into a subfolder. + +After a install of a newer version of miSCellaneous do a SCDoc update by + +code:: +SCDoc.indexAllDocuments(true) +:: + + +SECTION::License + +miSCellaneous is distributed under the GNU Public License in accordance with SuperCollider. +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +SECTION::Contact + +Email: daniel-mayer@email.de + +URL: link::http://daniel-mayer.at:: + + +SECTION::Credits + +Many thanks to James McCartney for developing SuperCollider, +Alberto de Campo for showing me its capabilities, +Wouter Snoei for his nice slider classes in wslib, +Nathaniel Virgo for his suggestions for feedback, +David Pirrò for his hints concerning ODE integration, +James Harkins for his remarks on many things and +the whole community for contributions and hints ! + + +SECTION::History + + +v0.23 2020-04-19 + +list:: +## ZeroXBufWr, ZeroXBufRd, TZeroXBufRd: playing half wavesets with demand rate control +## Remove doubled method lincurve_3_9, which caused a warning without harm +## AddEventTypes_PbindFx: use store instead of writeDefFile in private methods +## Minor fixes in help files +:: + +v0.22 2019-08-14 + +list:: +## Fb1_ODE and related: ordinary differential equation integration +## Fb1: now also runs at control rate, Fb1.new is equivalent to Fb1.ar +## Fb1: minor change of forced graph ordering +## PbindFx: accept instruments/fxs given as Strings in pbindData key/value pairs +## Minor fixes in help files +:: + +v0.21 2018-07-25 + +list:: +## Fb1: single sample feedback / feedforward +## GFIS: generalized functional iteration synthesis +## Redefined variables in Sieve, PSrecur and PSPdiv to enable inlining +## Minor fixes in help files +:: + +v0.20 2018-05-21 + +list:: +## Idev suite, search for numbers with integer distance from a source +## Bug fix in Integer method lcmByFactors +## Minor fixes in help files +:: + +v0.19 2017-11-22 + +list:: +## DX, a suite of pseudo ugens for crossfaded mixing and fanning +## Minor adaption of PbindFx event type +## Minor fixes in help files +:: + +v0.18 2017-09-26 + +list:: +## PLbindef / PLbindefPar: new features and implementation +## Minor fixes in PV_BinGap and PV_BinRange +## Minor fixes in help files +:: + + +v0.17 2017-08-21 + +list:: +## Smooth Clipping and Folding, a suite of pseudo ugens +## Added MIDI learning feature for VarGui slider control +## Platform.miSCellaneousDirs, search for miSCellaneous folder +## Adapted PV_BinRange and PV_BinGap to do multichannel expansion +## Exchanged graphic examples in VarGui help (Qt now) +## Minor fixes in help files +## First version released via GitHub and as Quark +:: + + +v0.16 2017-03-03 + +list:: +## Added PSPdiv, a dynamic multi-layer pulse divider based on Pspawner +## Added tutorial: Live Granulation +## Dropped miSCellaneous' b-branch: Cocoa and SwingOSC no longer supported +## Replaced OSCpathResponder by OSCFunc in classes VarGuiPlayerSection, HelpSynth and HelpSynthPar +## Minor fixes in help files +:: + + +v0.15 2017-01-04 + +list:: +## Guide "Introduction to miSCellaneous" +## kitchen studies: source code of the corresponding fixed media piece +## PV_BinRange, PV_BinGap: FFT pseudo ugens for defining bin ranges +## PbindFx help: new example 4a for defining implicit fx parallelism +## Minor fixes (help files, typos) +## Complemeting history information (tutorials) +:: + + +v0.14 2016-08-25 + +list:: +## Sieves and Psieve patterns, an implementation of Xenakis' sieves +## PLbindef / PLbindefPar: replacement of key streams in pseudomethod syntax +## Tutorial: PLx and live coding with Strings +## PsymNilSafe, method symplay: avoid hangs with nil input +## EventShortcuts: reworking of replacement, new method eventShortcuts +## PbindFx: reworking of bus match check +## Minor fixes (help files, typos) +:: + + +v0.13 2015-10-28 + +list:: +## PbindFx: Event pattern class for effect handling on per-event base +## Minor fixes (help files, typos) +:: + + +v0.12 2015-05-03 + +list:: +## PmonoPar, PpolyPar: Event pattern classes for parallel setting streams and effect handling +## PSloop: Pattern to derive loops from a given Pattern +## Reworked replacing options of PL list patterns: cutItems arg +## PLn: PLx Pattern for replacing with protecting periods +## Added PLxrand, PLx version of Pxrand +## Changed implementations of PStream (PS) and PSrecur, +now the MemoRoutine isn't instantiated before embedding, this enables use of PSx patterns with VarGui +## Fixed a bug in PL list patterns (PL_PproxyNth) that caused too early +replacements in certain cases +## Added method bufSeq for PStream +## Added missing help file of PLtuple +## Minor fixes (help files, typos) +:: + + +v0.11 2015-02-02 + +list:: +## Tutorial: link::Tutorials/Event_patterns_and_array_args:: +:: + + +v0.10 2014-10-06 + +list:: +## Split into branches 0.10a (3.7 onwards) and 0.10b (from 3.4 up to 3.6.x), with SC 3.7 SwingOSC and Cocoa aren't supported anymore. +## Class link::Classes/EventShortcuts:: and tutorial link::Tutorials/Other_event_and_pattern_shortcuts::. +:: + + +v0.9 2014-02-18 + +list:: +## PSx stream patterns (classes and tutorial), based on class MemoRoutine +## Buffer Granulation Tutorial: new examples (1c - 1e, 3d) +## VarGui save dialog fix (was broken with 3.6) +## Minor fixes (help files, typos) + +:: + +v0.8 2013-05-05 + +list:: +## Enumeration tutorial: method enum + +:: + +v0.7.1 2013-04-28 + +list:: +## Fix in PLseries and PLgeom + +:: + + +v0.7 2012-08-31 + +list:: +## Buffer Granulation tutorial file +## VarGui +list:: +## Support of wslib slider classes EZSmoothSlider and EZRoundSlider +## Color grouping options for synth and envir variable control +## Adapting EZSlider to ControlSpec step size (fixes certain rounding and jitter issues) +## Multiple slider handling with modifier keys: fixes and cleanup +:: + +:: + +v0.6 2012-05-19 + +list:: +## PLx dynamic scope pattern suite + +list:: +## Implementation of a number of common Patterns as PLx classes +## Tutorial PLx suite +## Changing examples in some previous help files accordingly + +:: + + +## Pstream, PlaceAll, Pshufn +:: + + +v0.5 2012-03-18 + +list:: +## VarGui shortcut build methods + +list:: +## Use of SynthDef metadata and global ControlSpecs +## Tutorial VarGui shortcut builds +## Automatic Pbind generation +:: + + +## Minor fixes in VarGui init procedure +:: + + +v0.4 2011-12-27 + +list:: +## VarGui support for HS family classes +## Tutorial HS with VarGui +## VarGui takes addAction as slider hook + +## Linux check (tested on Ubuntu): + +list:: +## Fixed system time issue in HS family +## Specified VarGui appearance default parameters for platform and gui kit +:: + +## Supports SCDoc, the new SC help system +## Tutorial Event Patterns and Functions +## Tutorial Event patterns and LFOs +## Play methods of PHSx and PHSxPlayer now also take numbers as quant arg +## Minor fixes in HS family +:: + + +v0.4_beta 2011-08-18 + +list:: +## VarGui relaunch: + +list:: +## Player section for Synths, EventStreamPlayers and Tasks +## Different player modes +## Button colors and background colors reflecting playing states +## Handling groups of players and sliders with modifier keys +## Player action by mouse down or up +## Variables can be set in different environments +## Latency setting, global and for synth player message bundling +## GUI appearance customization in size, arrangement and color +## Many other changes, e.g. arg conventions +:: + +## Private extension methods get prefix miSC_ +:: + +v0.3 2010-10-21 + +list:: +## VarGui: +list:: +## Arrayed synth control supported +## Slider update methods added +## Save dialog now uses unified gui class Dialog +:: +## Again compiling with SC 3.3 and 3.3.1 +:: + +v0.2 2010-09-18 + +list:: +## Minor adaptions to SC 3.4 +## Fixed time shifting issue +:: + +v0.1 2009-11-24 + +list:: +## VarGui, interface for envir variable and synth arg control +## HS / HSpar etc.: classes for the use of synth values in Pbind-like objects +## Tutorial Working with HS and HSpar +:: + diff --git a/HelpSource/Tutorials/Buffer_Granulation.schelp b/HelpSource/Tutorials/Buffer_Granulation.schelp new file mode 100755 index 0000000..16e4705 --- /dev/null +++ b/HelpSource/Tutorials/Buffer_Granulation.schelp @@ -0,0 +1,1695 @@ + + +TITLE::Buffer Granulation +summary::different approaches to buffer granulation with gui examples +categories:: Libraries>miSCellaneous>General Tutorials, Streams-Patterns-Events +related:: Tutorials/Live_Granulation, Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Tutorials/PLx_suite, Classes/PbindFx, Tutorials/kitchen_studies, Tutorials/Sieves_and_Psieve_patterns, Classes/PSPdiv, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +As with many things in SC work can be done by language or server. Speaking about granulation in general this mainly concerns the control of single grains, their rate, timing, length and other parameters. Regarding buffer granulation specifically this task can e.g. be taken over by ugens like TGrains and GrainBuf, the latter additionally accepting a grain envelope arg. The SC plugin distribution contains further variations (see BhobUGens, JoshUGens). By using granulation ugens in a SynthDef granular textures can be produced with a single Synth, including grain parameter sequencing with demand rate ugens, the link::Tutorials/DX_suite:: opens additional genuine options in this regard. Alternatively SynthDefs for single grains can be defined with PlayBuf or BufRd in order to control the whole buffer granulation process from language side, using Patterns, Tasks or Routines. What is the best way? To a large extent this is a question of personal preference. Regarding CPU performance granulation ugens have an advantage, whereas e.g. pattern-driven granulation allows concise control over the sequencing of granulation parameters in a clear syntax. If pattern-driven granulation is becoming CPU-critical you might want to consider the event type \grain, a lightweight variant of default type \note (see comment in the source file Event.sc). For granulation with Tasks see link::Classes/VarGui#Ex. 3#VarGui, Ex.3::. + +Also hybrid strategies are possible, e.g. language controlled setting of a single granulation Synth or involving extra control synths in a language-driven granulation process, further options are Pspawner / Pspawn and Wavesets. VarGui can be used to integrate these setups in single GUIs. Together with this file (miSCellaneous v0.7) I reinvented a color grouping option that overrides automatic color grouping (link::Classes/VarGui#Ex. 7#VarGui, Ex.7::). The latter is based on the logical structure of ordinary and array controls, synths and environments. This is useful for VarGuis up to a medium number of controls per Synth / Pattern / Task and also for a large number of such items, but it doesn't handle cases well where there are many controls per item. Not barely an aesthetic detail, it is much more convenient for experimenting to group all sliders of a Synth that, say, have to do with a bandpass filter, within one color. + +subsection::Types of variables + +In general interpreter variables are prefered in examples below, wherever possible. If evaluated with example code only their values are passed and further changing of used variables doesn't affect already generated gui instances. On the contrary repeated evaluation of an interpreter variable, e.g. from a Pfunc, is unsafe - variable's value could change while gui has not yet been closed - so in concerned examples values are passed to the event definition, in link::#Ex.2c:: a variable is declared for the same reason. +The use of environmental variables is following the way VarGui is handling them. Per default every EventStreamPlayer derived from a passed Pattern is run in a separate newly generated Environment, where variables are being set and Streams from Pfuncs and PLx patterns are reading from. See link::Tutorials/Event_patterns_and_Functions::, link::Tutorials/PLx_suite:: and link::Classes/VarGui::. + + + +warning:: + +numberedList:: + +## Be careful with amplitudes, especially with buffers you haven't granulated before! Also keep in mind that a granular cloud moving through a buffer can suddenly become louder and other controls than amp (e.g. buffer position, trigger rate, bandpass parameters) can cause a raise of amplitude too. + + +## I haven't used below setups for live performances. Although all of them work stable for me as they are, in general hangs can occasionally happen with pattern-driven setups. Often this can be tracked down to sequences of extremely short event durations (and/or long grain durations). Where this can happen as a side-effect, thresholds can be built in, e.g. link::#Ex.2d:: (Wavesets) has a parameter maxTrigRate. +Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended - and if more complications are involved: testing without sound first, after saving your patch, might be a good idea. +:: +:: + +note:: +All variants from this tutorial can be applied to a buffer, which is occasionally (or continuously) filled with live input. Vice versa variants from link::Tutorials/Live_Granulation:: can of course be applied to any signal, thus also to any playback of a buffer. + +All examples below expect mono buffers. Buffer paths refering to the included sample suppose that you have installed via quarks or moved miSCellaneous lib into the user or system extensions directory directly (not into a subfolder), if not so or you have moved the sample file somewhere else you'd have to change paths accordingly. + +Due to a bug in SC 3.7 / 3.8 TGrains didn't response to amp changes, I changed the examples accordingly, the bug is fixed in 3.9. + +While other parts of miSCellaneous lib were running fine I was unable to allocate buffers with the SC 3.5.4 Windows binary in August 2012. Meanwhile this issue has been solved (SC 3.6.6, February 2014). There also seemed to be accuracy issues with OffsetOut on Windows with SC 3.6 still, but not with newer versions. +:: + + + +subsection::Credits + +Thanks for contributions and inspirations by SCers Alberto de Campo (Wavesets), James Harkins (Patterns), Ron Kuivila (Pspawner), Sergio Luque (stochastic distributions), Josh Parmenter (granulation plugins), Bhob Rainey (granulation plugins). + +subsection::References + +numberedList:: + +## de Campo, Alberto. "Microsound" In: Wilson, S., Cottle, D. and Collins, N. (eds). 2011. The SuperCollider Book. Cambridge, MA: MIT Press, 463-504. + +## Luque, Sergio (2006). Stochastic Synthesis, Origins and Extensions. Institute of Sonology, Royal Conservatory, The Netherlands. http://sergioluque.com + +## Roads, Curtis (2001). Microsound. Cambridge, MA: MIT Press. + +## Seidl, Fabian (2016). Granularsynthese mit Wavesets für Live-Anwendungen. Master Thesis, TU Berlin. http://www2.ak.tu-berlin.de/~akgroup/ak_pub/abschlussarbeiten/2016/Seidl_MasA.pdf + +## Wishart, Trevor (1994). Audible Design. York: Orpheus The Pantomime Ltd. + +## Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition. + +:: + + + +anchor::1:: +SECTION::1. Granulation with Ugens +subsection::Ex.1a: Basic buffer granulation Synth + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +// basic SynthDef suited for pitch-shift and time-stretch +// buffer position given relatively (posLo and posHi between 0 and 1) +// posDev: maximum amount of deviation from (moving) grain center position +// posDev = 0 can lead to comb filter effects (which may be nice sometimes) + +// passing control specs as metadata allows for VarGui shortcut build method sVarGui +// metadata specs can be overwritten by arg ctrReplace +// alternatively control specs may be passed as synthCtr arg to a build with VarGui( ... ) + +( +SynthDef(\gran_1a, { arg out = 0, bufNum = 0, posLo = 0.0, posHi = 1.0, + posRate = 1, posDev = 0.01, trigRate = 100, granDur = 0.1, rate = 1.0, + panMax = 1, amp = 0.1, interp = 4; + + var trig, pan, pos, bufDur, bufDurSection, posDif; + + posDif = posHi - posLo; + bufDur = BufDur.kr(bufNum); + bufDurSection = bufDur * posDif; + trig = Impulse.kr(trigRate); + pos = posLo * bufDur + + (Phasor.ar(0, BufRateScale.kr(bufNum) * posRate / SampleRate.ir, posLo * bufDur, posHi * bufDur) + + (TRand.kr(-0.5 * posDev, 0.5 * posDev, trig) * bufDur)).mod(bufDurSection); + pan = Demand.kr(trig, 0, Dseq([panMax, panMax.neg],inf) * 0.999); + Out.ar(out, TGrains.ar(2, trig, bufNum, rate, pos, granDur, pan, 1, interp) * amp); + }, metadata: ( + specs: ( + posLo: [0.01, 0.99, \lin, 0.01, 0], + posHi: [0.01, 0.99, \lin, 0.01, 1], + posRate: [0.1, 2, \lin, 0.01, 1], + posDev: [0, 0.2, 5, 0, 0.01], + granDur: [0.01, 0.3, \lin, 0.01, 0.1], + trigRate: [1, 200, \lin, 0.01, 100], + rate: [0.1, 2, \lin, 0.01, 1], + panMax: [0.0, 1, \lin, 0.005, 0.8], + amp: [0.0, 0.5, \lin, 0.005, 0.25] + ) + ) +).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +) + + +// start from GUI + +\gran_1a.sVarGui([\bufNum, b.bufnum]).gui; + + +:: + +anchor::Ex.1b:: +subsection::Ex.1b: More deviations + +code:: + +// In example 1a only a deviation from the grain center position was implemented. +// With additional deviation controls a greater plasticity of sound can be achieved, +// here deviations are added for trigRate (LFO with oscillation freq and deviation max), +// grain duration and rate (TRand, equally weighted random deviation with given max). +// Deviations intervals could be defined alternatively, +// e.g. (1/(1+maxDev), 1+maxDev) with 0 < maxDev +// instead of (1-maxDev, 1+mexDev) with 0 < maxDev < 1 + +// posRate control range is widened by inventing two controls for +// mantissa and exponent, so posRate = 1 for init param pair +// posRateE = 0 and posRateM = 1 + +( +SynthDef(\gran_1b, { arg out = 0, bufNum = 0, posLo = 0.0, posHi = 1.0, + posRateE = 0, posRateM = 1, posDev = 0.01, trigRate = 100, trigRateDev = 0, + trigRateOsc = 1, granDur = 0.1, granDurDev = 0, rate = 1.0, rateDev = 0, + panMax = 1, amp = 0.1, interp = 4; + + var trig, pan, pos, bufDur, bufDurSection, posDif, posRate; + + posDif = posHi - posLo; + bufDur = BufDur.kr(bufNum); + bufDurSection = bufDur * posDif; + trig = Impulse.kr(LFDNoise3.kr(trigRateOsc, trigRate * trigRateDev, trigRate)); + posRate = 10 ** posRateE * posRateM; + pos = posLo * bufDur + + (Phasor.ar(0, BufRateScale.kr(bufNum) * posRate / SampleRate.ir, posLo * bufDur, posHi * bufDur) + + (TRand.kr(-0.5, 0.5, trig) * posDev * bufDur)).mod(bufDurSection); + pan = Demand.kr(trig, 0, Dseq([panMax, panMax.neg],inf) * 0.999); + Out.ar(out, TGrains.ar(2, trig, bufNum, rate * (TRand.kr(-1, 1.0, trig) * rateDev + 1), pos, + granDur * (TRand.kr(-1, 1.0, trig) * granDurDev + 1), pan, 1, interp) * amp); + }, metadata: ( + specs: ( + posLo: [0.01, 0.99, \lin, 0.01, 0], + posHi: [0.01, 0.99, \lin, 0.01, 1], + posRateE: [-3, 4, \lin, 1, 0], + posRateM: [0.1, 10, \exp, 0.01, 1], + posDev: [0, 0.2, 5, 0, 0.05], + trigRate: [1, 200, \lin, 0.01, 100], + trigRateDev: [0.0, 1, \lin, 0.01, 0], + trigRateOsc: [0.1, 2, \lin, 0.01, 3], + granDur: [0.01, 0.3, \lin, 0.01, 0.1], + granDurDev: [0.0, 0.95, \lin, 0.01, 0], + + rate: [0.1, 2, \lin, 0.01, 1], + rateDev: [0.0, 0.99, \linear, 0.01, 0.05], + panMax: [0.0, 1, \lin, 0.005, 0.8], + amp: [0.0, 0.5, \lin, 0.005, 0.25] + ) + ) +).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. +) + + +// start from GUI +// use color grouping for better overview + +\gran_1b.sVarGui([\bufNum, b.bufnum]).gui(synthColorGroups: (0..14).clumps([1,5,3,2,2,1,1]) ) + +:: + + +subsection::Ex.1c: Buffer granulation Synth with external control synths + +code:: + +// This is a more modular approach, once having a basic granulation synth +// it can be linked with arbitrary control synths, here +// also moving through the buffer is controlled externally. +// Depending on LFOs it might be worth defining +// audio buses for control to get higher precision. + + +( +SynthDef(\gran_1c, { arg out = 0, bufNum = 0, amp = 0.1, pos = 0.5, posDev = 0.01, + trigRate = 100, granDur = 0.1, rate = 1, panMax = 1, interp = 4; + var trig, pan; + trig = Impulse.kr(trigRate); + pan = Demand.kr(trig, 0, Dseq([panMax, panMax.neg],inf) * 0.999); + pos = (pos * BufDur.kr(bufNum) * WhiteNoise.kr(posDev, 1)); + Out.ar(out, TGrains.ar(2, trig, bufNum, rate, pos, granDur, pan, 1, interp) * amp); +}).add; + + +// LFO synthdef for switching between 3 types: +// 0: LFDNoise3 (smooth random movement) +// 1: SinOsc +// 2: LFSaw (works as phasor for position) + +SynthDef(\lfo, { |out = 0, lfoType = 0, freq = 1, lo = 0, hi = 1| + var ctrl; + ctrl = Select.kr(lfoType, [ + LFDNoise3, + SinOsc, + LFSaw + ].collect { |x| x.kr(freq, mul: hi-lo/2, add: hi+lo/2) }); + Out.kr(out, ctrl); +}).add; + +// multichannel control bus +c = Bus.control(s, 5); + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. +) + + +// In contrast to Ex. 1a and 1b VarGui is called explicitely +// as control specs should differ. + +// Also here the granulation Synth is generated explicitely and not by the interface +// as its controls have to be mapped to buses + +( +// start granulation synth paused and register +// to let VarGui know its state + +x = Synth.newPaused(\gran_1c, [\bufNum, b]).register; + +// map args to be controlled to consecutive subbuses +x.map(*[[\pos, \trigRate, \granDur, \rate, \panMax], (0..4).collect(c.subBus(_))].flop.flat) +) + +( +// Open VarGui interface, granulation synth (#5) is paused +// (orange button on yellow background). +// Shift-clicking one of the green buttons runs +// granulation synth and control synths (#0 - #4). +// All synths can be paused (orange button) and resumed. + +// NOTE: When stopping the granulation synth +// the linkage with control synths is lost! +// A new synth generated by the interface +// (by pressing the blue button of #5) is not +// automatically mapped to control buses. +// On the other hand control synths might be stopped and +// newly generated. + + +VarGui(synthCtr: [[ + \pos, 0, // dummy spec for labelling + \out, c.index, + \lfoType, [0, 2, \lin, 1, 0], + // as LFOs are unified, original movement tempo is + // indicated not by 1 but by 1 / buffer duration + \freq, [0.01, 20, \exp, 0.0, 1/b.duration], + \lo, [0.0, 1, \lin, 0, 0.1], + \hi, [0.0, 1, \lin, 0, 0.9] + ],[ + \trigRate, 1, + \out, c.index + 1, + \lfoType, [0, 2, \lin, 1, 0], + \freq, [0.001, 0.5, \exp, 0.0, 0.2], + \lo, [1, 100, \lin, 0, 7], + \hi, [1, 100, \lin, 0, 40] + ],[ + \granDur, 2, + \out, c.index + 2, + \lfoType, [0, 2, \lin, 1, 1], + \freq, [0.001, 0.5, \exp, 0.0, 0.4], + \lo, [0.01, 0.2, \lin, 0, 0.1], + \hi, [0.01, 0.2, \lin, 0, 0.15] + ],[ + \rate, 3, + \out, c.index + 3, + \lfoType, [0, 2, \lin, 1, 0], + \freq, [0.001, 0.1, \exp, 0.0, 0.03], + \lo, [0.1, 3, \lin, 0, 0.6], + \hi, [0.1, 3, \lin, 0, 1.1] + ],[ + \panMax, 4, + \out, c.index + 4, + \lfoType, [0, 2, \lin, 1, 0], + \freq, [0.001, 0.5, \exp, 0.0, 0.5], + \lo, [0.0, 1, \lin, 0, 0.06], + \hi, [0.0, 1, \lin, 0, 0.9] + ],[ + \out, 0, + \bufNum, b.bufnum, + \posDev, [0.001, 0.2, \exp, 0, 0.02], + \amp, [0.0, 2, \lin, 0, 0.5] + ]], + // 5 lfo synths are generated by the interface (synthdef name passed) + // but granulation Synth is passed directly as object + synth: \lfo!5 ++ x +).gui(sliderPriority: \synth, playerPriority: \synth); +) + +:: + +subsection::Ex.1d: Buffer granulation Synth with demand rate ugens + +code:: + +// Repeated grain triggering within a synth can be defined by demand rate ugens, +// which is comfortable in connection with granular ugens. + +// E.g. with TGrains you can trigger parameters like grain duration, playback rate, +// position, panning and amp, single grains will keep their params if they overlap. +// (Note that in the below implementation changes of demand rate array fields will apply +// also not before the next call of those fields in the synth) + +// More refined per-grain control, e.g. per-grain filtering with filter parameter streams, +// can be done by using a multichannel trick, see Ex. 1e. + +( +// length of demand rate sequence, you might want to check larger sizes +// in connection with gui arg tryColumnNum > 1 +~n = 5; + +// posRate control range is widened by inventing two controls for +// mantissa and exponent, so posRate = 1 for init param pair +// posRateE = 0 and posRateM = 1 + +SynthDef(\gran_1d, { |out = 0, soundBuf, posLo = 0.1, posHi = 0.3, + posRateE = 0, posRateM = 1, granDurMul = 1, rateMul = 1, panMul = 1, amp = 0.5, interp = 2| + + var signal, bufDur, granDur, granGate, relGranDurs, pos, overlap, overlaps, overlapSeq, + pan, rate, relRates, rateSeq, posRate, granDurSeq; + + // array args for demand rate sequencing, short form of NamedControl + relGranDurs = \relGranDurs.kr(0.1!~n); + relRates = \relRates.kr(1!~n); + overlaps = \overlaps.kr(1!~n); + + // Dstutter (or Dunique) necessary as granDurSeq is polled twice: granGate and granDur + granDurSeq = Dstutter(2, Dseq(relGranDurs, inf)); + rateSeq = Dseq(relRates, inf); + overlapSeq = Dseq(overlaps, inf); + + granGate = TDuty.ar(granDurSeq * granDurMul); + granDur = Demand.ar(granGate, 0, granDurSeq * granDurMul); + rate = Demand.ar(granGate, 0, rateSeq) * rateMul; + pan = Demand.ar(granGate, 0, Dseq([1, -1], inf)) * 0.999 * panMul; + overlap = Demand.ar(granGate, 0, overlapSeq); + + bufDur = BufDur.kr(soundBuf); + posRate = 10 ** posRateE * posRateM; + + pos = Phasor.ar(0, BufRateScale.kr(soundBuf) * posRate / (SampleRate.ir * bufDur), posLo, posHi); + signal = TGrains.ar(2, granGate, soundBuf, rate, pos * bufDur, granDur * overlap, pan, 1, interp); + + Out.ar(out, signal * amp); +} +).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. +) + +( +// relGranDurs are multiplied with granDurMul, analogously relRates with rateMul. +// Changes of these params apply immediately in contrast to the array args +// used by demand rate ugens which are used with next demand. + +// check out moving a number of sliders of one array by using +// Shift, Alt + Shift and Ctrl + Shift, see VarGui help Ex. 1c. + + +VarGui(synthCtr: [ + soundBuf: b.bufnum, + + posLo: [0, 1, \lin, 0, 0.1], + posHi: [0, 1, \lin, 0, 0.9], + posRateE: [-3, 4, \lin, -1, 0], + posRateM: [0.1, 10, \exp, 0.01, 0.5], + + // generating control specifications depending on index + relGranDurs: { |i| [0.01, 0.1, \lin, 0, i * 0.005 + 0.02] } ! ~n, + granDurMul: [0.03, 2, \lin, 0, 0.25], + overlaps: [0.1, 5, \lin, 0, 1.5] ! ~n, + + relRates: { |i| [0.1, 1.5, \lin, 0, (5-i) * 0.1 + 0.5] } ! ~n, + rateMul: [0.1, 2, \lin, 0, 0.5], + + panMul: [0, 1, \lin, 0, 0.6], + amp: [0.0, 3, \lin, 0, 2] +], + synth: \gran_1d +).gui( + tryColumnNum: 1, + // color grouping for better overview + synthColorGroups: (0..(~n*3+8)).clumps([1,4,~n+1,~n,~n+1,1,1]), + labelWidth: 90, + sliderWidth: 280 +); +) +:: + +anchor::Ex.1e:: +subsection::Ex.1e: Buffer granulation Synth with per-grain effect processing (TGrains) + +code:: + +// TGrains and other granular ugens allow per-grain processing +// for a limited number of parameters (pos, rate etc.) +// Nevertheless it is possible to apply arbitrary effects with +// per-grain parameter changes, even if grains overlap. +// This can be achieved by defining the granulation output +// as a multichannel signal and appropriate triggering of fx parameters. +// The example is adapted from a recommendation of Julian Rohrhuber. + +// The method is elegant but also a bit tricky in terms of +// multichannel triggering and channel routing. +// See Ex.1f for achieving the same with DX ugens + +( +// the multichannel size and equivalently: +// the maximum number of overlapping grains that might get +// different fx parameters have to be fixed. +// For convenience of later L/R-spatialization we take an +// even number ~n = 2 * ~m + +~m = 5; +~n = 2 * ~m; + +SynthDef(\gran_1e, { |out = 0, soundBuf, posLo = 0.1, posHi = 0.9, + posRateE = 0, posRateM = 1, rate = 1, panMax = 0.8, bpRQ = 0.1, bpLo = 50, bpHi = 5000, + amp = 1, bpFund = 100, overlap = 2, trigRate = 1, interp = 2| + var sig, sigL, sigR, bpFreq, chan, bpFreqSeqs, dUgen, + trig, trigs, bufDur, pos, posRate; + + trig = Impulse.ar(trigRate); + // we need a multichannel trigger that steps through all consecutive channels + trigs = { |i| PulseDivider.ar(trig, ~n, ~n-1-i) } ! ~n; + + chan = Demand.ar(trig, 0, Dseq((0..~n-1), inf)); + + posRate = 10 ** posRateE * posRateM; + bufDur = BufDur.kr(soundBuf); + pos = Phasor.ar(0, BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, posLo, posHi); + + sig = TGrains.ar(~n, trig, soundBuf, rate, pos * bufDur, overlap/trigRate, + // Panning convention is that from PanAz, + // speakers should be from 0 to 2, but (orientation) + // 1/n has to be substracted for n speakers. + // If this isn't done correctly grains are spread onto more than one channel + // and per-grain application of fxs fails. + chan.linlin(0, ~n-1, -1/~n, (2*~n - 3)/~n), 1, interp); + + dUgen = Dwhite(0.0, 1); + sig = sig.collect { |ch, i| + // this is the place to define fxs per channel/grain + // multichannel trigger is polling from a single demand ugen + bpFreq = Demand.ar(trigs[i], 0, dUgen).linlin(0, 1, bpLo, bpHi); + + // amplitude compensation for lower rq of bandpass filter + BPF.ar(ch, bpFreq, bpRQ, (bpRQ ** -1) * (400 / bpFreq ** 0.5)); + }; + + // routing to two channels ... + sigL = Mix(((0..(~m-1)) * 2).collect(sig[_])); + sigR = Mix(((0..(~m-1)) * 2 + 1).collect(sig[_])); + + // ... in order to have L/R-spreading with panMax as in other examples + Out.ar(0, Pan2.ar(sigL, panMax.neg) + Pan2.ar(sigR, panMax) * amp) +}).add; + + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. +) + + +( +VarGui(synthCtr: [ + soundBuf: b.bufnum, + posLo: [0, 1, \lin, 0, 0.2], + posHi: [0, 1, \lin, 0, 0.5], + posRateE: [-3, 4, \lin, -1, -1], + posRateM: [0.1, 10, \exp, 0.01, 0.8], + overlap: [0.1, ~n, \lin, 0, 12], + trigRate: [1, 100, \lin, 0, 45], + rate: [0.1, 2, \lin, 0, 1], + + bpRQ: [0.05, 1, \lin, 0, 0.25], + bpLo: [50.0, 5000, \exp, 0, 50], + bpHi: [50.0, 5000, \exp, 0, 5000], + panMax: [0, 1, \lin, 0, 0.85], + amp: [0.0, 3, \lin, 0, 1] +], + synth: \gran_1e +).gui( + tryColumnNum: 1, + synthColorGroups: (0..12).clumps([1,4,2,1,3,1,1]) +); +) +:: + +anchor::Ex.1f:: +subsection::Ex.1f: Buffer granulation Synth with per-grain effect processing (DXEnvFan) + +code:: +// DXEnvFan generates a multichannel envelope which can be used as trigger for granulation and fxs on grains. +// It encapsulates the trigger logic, which has been used explicitely in Ex. 1e. +// DX ugens can be used for a variety of microsound techniques, see their help files. + +( +~maxOverlap = 12; +a = Bus.audio(s, ~maxOverlap); + +// overlap only settable in SC versions >= 3.9 + +SynthDef(\gran_1f, { |out = 0, soundBuf, bus = 0, posLo = 0.1, posHi = 0.9, + posRateE = 0, posRateM = 1, overlap = 2, trigRate = 1, rate = 1, + bpRQ = 0.1, bpLo = 50, bpHi = 5000, panMax = 0.8, amp = 1| + var sig, bpFreq, dUgen, bufDur, pos, posRate, playbuf, env, maxOverlap = ~maxOverlap; + + posRate = 10 ** posRateE * posRateM; + bufDur = BufDur.kr(soundBuf); + pos = Phasor.ar(0, BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, posLo, posHi); + + // multichannel trigger + env = DXEnvFan.ar( + Dseq((0..maxOverlap-1), inf), + trigRate.reciprocal, + size: maxOverlap, + maxWidth: maxOverlap, + width: (Main.versionAtLeast(3, 9)).if { overlap }{ 2 }, + // option to avoid unwanted triggers + zeroThr: 0.002, + // take equalPower = 0 for non-squared sine envelopes + // more efficient with helper bus + equalPower: 0, + bus: a + ); + // multichannel playback, pos is triggered for each grain + playbuf = PlayBuf.ar(1, soundBuf, rate, env, pos * BufFrames.ir(soundBuf), 1); + + dUgen = Dwhite(0, 1); + // multichannel trigger used to poll values from drate ugen + bpFreq = Demand.ar(env, 0, dUgen).linlin(0, 1, bpLo, bpHi); + + // generate grains by multiplying with envelope + sig = playbuf * env; + + // different frequency on each grain channel + sig = BPF.ar(sig, bpFreq, bpRQ, (bpRQ ** -1) * (400 / bpFreq ** 0.5)); + + // generate array of 5 stereo signals + sig = Pan2.ar(sig, Demand.ar(env, 0, Dseq([-1, 1], inf) * panMax)); + + // mix to out + Out.ar(0, Mix(sig) * amp) +}, metadata: ( + specs: ( + posLo: [0.01, 0.99, \lin, 0.01, 0], + posHi: [0.01, 0.99, \lin, 0.01, 0.5], + posRateE: [-3, 4, \lin, 1, -1], + posRateM: [0.1, 10, \exp, 0.01, 1.35], + trigRate: [1, 200, \lin, 0.01, 90], + overlap: [0.2, 12, \lin, 0.01, 7], + rate: [0.1, 2, \lin, 0.01, 0.75], + panMax: [0.0, 1, \lin, 0.005, 0.75], + bpLo: [100, 5000, \lin, 0, 300], + bpHi: [100, 5000, \lin, 0, 3000], + bpRQ: [0.05, 1, \lin, 0, 0.18], + amp: [0.0, 3, \lin, 0.005, 1] + ) +)).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. +) + +( +\gran_1f.sVarGui([\soundBuf, b.bufnum]).gui( + tryColumnNum: 1, + synthColorGroups: (0..12).clumps([1,4,2,1,3,1,1]) +) +) +:: + + +anchor::Ex.1g:: +subsection::Ex.1g: Buffer granulation with (half) wavesets: ZeroXBufRd + +code:: +// movement through the buffer of zero crossings +// with a slow pos rate we get repetitions of half wavesets + +// load sound buffer + +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + + +// allocate zeroX buffer + +( +z = Buffer.alloc(s, b.duration * 44100 / 5, 1); +s.scope; +) + + +// write zero crossings, but no need to overwrite sound buffer +// this is caused by setting adjustZeroXs to -1 + +( +{ + // use LeakDC to avoid extremely long half wavesets + var src = LeakDC.ar(PlayBuf.ar(1, b, BufRateScale.ir(b))); + ZeroXBufWr.ar(src, b, z, adjustZeroXs: -1, doneAction: 2); +}.play +) + + +// instead adjust from lang and get zeroXs + +b.adjustZeroXs(z, { |z| ~zeroXs = z.reject(_==0) }) + +// get number of zeroXs + +~zeroXNum = ~zeroXs.size + + +( +SynthDef(\gran_1g, { |out = 0, soundBuf, zeroXBuf, zeroXNum, posLo = 0.1, posHi = 0.9, + posRateE = 0, posRateM = 1, rate = 1, amp = 1| + var sig, bufDur, pos, posRate; + + posRate = 10 ** posRateE * posRateM; + bufDur = BufDur.kr(soundBuf); + + // move through the buffer of zero crossings + // the tempo (rate) refers to the sound buffer + pos = Phasor.ar( + 0, + BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, + posLo, + posHi + ) * zeroXNum; + + sig = ZeroXBufRd.ar( + soundBuf, + zeroXBuf, + 0!2, + pos, + mul: amp, + rate: rate * [1, 1.01] + ); + Out.ar(0, sig * amp) +}, metadata: ( + specs: ( + posLo: [0.01, 0.99, \lin, 0.01, 0.1], + posHi: [0.01, 0.99, \lin, 0.01, 0.5], + posRateE: [-2, 2, \lin, 1, -1], + posRateM: [0.1, 10, \exp, 0.01, 3], + rate: [0.3, 3, \lin, 0.01, 1], + amp: [0.0, 2, \lin, 0.005, 1] + ) +) +).add; + +\gran_1g.sVarGui([\soundBuf, b.bufnum, \zeroXBuf, z.bufnum, \zeroXNum, ~zeroXNum]).gui +) +:: + + +anchor::Ex.1h:: +subsection::Ex.1h: Buffer granulation with (half) wavesets: TZeroXBufRd + +code:: +// buffer preparations from Ex. 1g + +// again a movement through the buffer of zero crossings is implemented +// the repetition of wavesets though is defined by xNum and xRep + +// with high trigger rates, xNum and xRep values and low rates you might +// have to increase overlapSize, see TZeroXBufRd help for a discussion of this topic + +( +SynthDef(\gran_1h, { |out = 0, soundBuf, zeroXBuf, zeroXNum, posLo = 0.1, posHi = 0.9, + posRateE = 0, posRateM = 1, xNum = 1, xRep = 1, rate = 1, trigRate = 100, amp = 1| + var sig, bufDur, pos, posRate; + + posRate = 10 ** posRateE * posRateM; + + bufDur = BufDur.kr(soundBuf); + pos = Phasor.ar( + 0, + BufRateScale.kr(soundBuf) * posRate * SampleDur.ir / bufDur, + posLo, + posHi + ) * zeroXNum; + + // move through the buffer of zero crossings + // the tempo (rate) refers to the sound buffer + sig = TZeroXBufRd.ar( + soundBuf, + zeroXBuf, + 0!2, // bufMix arg triggers stereo + trig: Impulse.ar(trigRate), + zeroX: pos, + xNum: xNum, + xRep: xRep, + mul: amp, + rate: rate * [1, 1.01], // a bit of decorrelation + overlapSize: 20 // larger overlapSize + ); + // by overlapping a DC can easily accumulate, so do leak + Out.ar(0, LeakDC.ar(sig) * amp) +}, metadata: ( + specs: ( + posLo: [0.01, 0.99, \lin, 0.01, 0.1], + posHi: [0.01, 0.99, \lin, 0.01, 0.5], + posRateE: [-2, 2, \lin, 1, -1], + posRateM: [0.1, 10, \exp, 0.01, 1], + rate: [0.3, 2, \lin, 0.01, 1], + trigRate: [5, 120, \lin, 0, 50], + xNum: [1, 5, \lin, 1, 2], + xRep: [1, 5, \lin, 1, 3], + amp: [0.0, 2, \lin, 0, 1] + ) +) +).add; + +\gran_1h.sVarGui([\soundBuf, b.bufnum, \zeroXBuf, z.bufnum, \zeroXNum, ~zeroXNum]).gui +) +:: + + +anchor::2:: +SECTION::2. Granulation driven by language + +subsection::Ex.2a: Basic buffer granulation Pbind + +note:: +Language-driven sequencing is not sample-exact in realtime (with NRT synthesis it is). This is related to hardware control and cannot be overcome currently. However for most practical purposes this might not be relevant. It is anyway a far less strong effect than the inaccuracies related to Out.ar and the combination of OffsetOut.ar and In.ar (see examples 2a-d in link::Tutorials/Live_Granulation::) +:: + + + +code:: + +// Control parameters like in Ex.1a, but implemented with a SynthDef for +// playing single grains and an appropriate Pbind, +// OffsetOut used for exact timing. + +( +SynthDef(\gran_2a, { |out = 0, pos = 0, sndBuf = 0, windowBuf = 1, granDur = 0.1, + rate = 1, loop = 1, panMax = 0, amp = 1| + var window, src; + src = PlayBuf.ar(1, sndBuf, BufRateScale.kr(sndBuf) * rate, + 1, round(pos * BufFrames.kr(sndBuf)), loop, 2); + window = BufRd.ar(1, windowBuf, + EnvGen.ar(Env([0, BufFrames.kr(windowBuf)], [granDur]), + doneAction: 2), loop, 4); + OffsetOut.ar(out, Pan2.ar(src, panMax, amp) * window); +}).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +w = Buffer.sendCollection(s, Signal.hanningWindow(1024)); +) + + +// Determining the correct buffer position depending on +// posRate, posLo and posHi needs a little calculation. +// In 1a this was done inside the ugen by a Phasor. +// See Ex.3b, 3c for doing position movement with a separate Synth. + +// PL placeholder patterns used, could also be Pfunc { ~ ... } + +( +p = Pbind( + \instrument, \gran_2a, + \sndBuf, b, + \windowBuf, w, + + \dur, 1 / PL(\trigRate), + \granDur, PL(\granDur), + \time, Ptime(), + \pos, Pfunc { |e| + var relTime = ~posRate * e.time / e.sndBuf.duration, relDif; + relDif = ~posHi - ~posLo; + relTime + rand2(~posDev) % relDif + ~posLo; + }, + \rate, PL(\rate), + \amp, PL(\amp), + \panMax, PLseq([-1,1]) * PL(\panMax), + \out, 0 +); + +VarGui([ + \posLo, [0.0, 0.99, \lin, 0.01, 0], + \posHi, [0.0, 0.99, \lin, 0.01, 1], + \posRate, [0.1, 2, \lin, 0.01, 1], + \posDev, [0, 0.2, 5, 0, 0.01], + \trigRate, [1, 200, \lin, 0.01, 120], + \granDur, [0.01, 0.3, \lin, 0.005, 0.06], + \rate, [0.1, 3, \lin, 0.01, 1], + \panMax, [0.0, 1, \lin, 0.0, 0.8], + \amp, [0.0, 1, \lin, 0.01, 0.25] + ], stream: p +).gui(varColorGroups: (0..8).clumps([4,1,1,1,1,1])) +) + +:: + +anchor::Ex.2b:: +subsection::Ex.2b: Switching between stochastic distributions + +code:: + +// Extended basic SynthDef from Ex.2a with bandpass filter + +( +SynthDef(\gran_2b, { |out = 0, pos = 0, sndBuf = 0, windowBuf = 1, granDur = 0.1, + rate = 1, loop = 1, panMax = 0, amp = 1, bpFreq = 500, bpRQ = 0.5, bpWet = 1| + var window, granSrc, src; + granSrc = PlayBuf.ar(1, sndBuf, BufRateScale.kr(sndBuf) * rate, + 1, round(pos * BufFrames.kr(sndBuf)), loop, 2); + window = BufRd.ar(1, windowBuf, + EnvGen.ar(Env([0, BufFrames.kr(windowBuf)], [granDur]), + doneAction: 2), loop, 4); + // do amplitude compensation, estimation like in Wavesets example by Alberto de Campo + src = (BPF.ar(granSrc, bpFreq, bpRQ, mul: (bpRQ ** -1) * (400 / bpFreq ** 0.5)) * + bpWet + (granSrc * (1 - bpWet))); + + OffsetOut.ar(out, Pan2.ar(src, panMax, amp) * window); +}).add; + + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +w = Buffer.sendCollection(s, Signal.hanningWindow(1024)); +) + + +// random types + +// 0: low value +// 1: low or high value, evenly distributed +// 2: evenly distributed +// 3: linear decrease from mean value +// 4: exponential distribution +// 5: beta distribution, default parameter 0.3 centers value at the borders +// 6: brownian movement (of first order) +// 7: brownian movement of second order (stepsize itself generated by brownian movement) + +// A second order brownian movement much more tends to get stuck at the +// borders than a normal (first order) brownian movement +// E.g. see Sergio Luque's presentation of Xenakis's stochastic synthesis: +// "Stochastic Synthesis, Origins and Extensions", pp 25-28 +// http://sergioluque.com + + +// Function that generates an array of PLx patterns +// of different random types (see PLx suite). +// These placeholders can refer to environmental variables +// to be set by the VarGui interface later on. + +( +d = { |keyLo, keyHi, betaProb = 0.3, brownStepFac = 0.01, + brown2Ratio = 1, brown2StepFac = 0.01| + // keyLo and keyHi must be Symbols, + // other args may be Symbols + var patLo, patHi, patDif; + + // avoid lo-hi reversing with Pbrown + patLo = min(PL(keyLo), PL(keyHi)); + patHi = max(PL(keyLo), PL(keyHi)); + patDif = patHi - patLo; + [ + PL(keyLo), + Pfunc { currentEnvironment[[keyLo, keyHi].choose] }, + PLwhite(keyLo, keyHi), + PLmeanrand(keyLo, keyHi), + PLexprand(keyLo, keyHi), + PLbeta(keyLo, keyHi, betaProb, betaProb), + PLbrown(patLo, patHi, patDif * PL(brownStepFac)), + PLbrown(patLo, patHi, + PLbrown( + patDif.neg * PL(brown2Ratio) / 2, + patDif * PL(brown2Ratio) / 2, + patDif * PL(brown2Ratio) * PL(brown2StepFac) + ) + ) + ] +}; +) + +// trigrate, granDur, rate and bpFreq are +// chosen between bounds according to the +// random distribution type notated with suffix D + +// single grains are filtered with a bandpass +// amount of effect controlled with bpWet + +( +p = Pbind( + \instrument, \gran_2b, + \sndBuf, b, + \windowBuf, w, + + \dur, 1 / PLswitch1(d.(\trigRateLo, \trigRateHi), \trigRateD), + \granDur, PLswitch1(d.(\granDurLo, \granDurHi), \granDurD), + \time, Ptime(), + \posRate, PL(\posRate), + \pos, Pfunc { |e| + var relTime = ~posRate * e.time / e.sndBuf.duration, relDif; + relDif = ~posHi - ~posLo; + relTime + rand2(~posDev) % relDif + ~posLo; + }, + \rate, PLswitch1(d.(\rateLo, \rateHi), \rateD), + \bpFreq, PLswitch1(d.(\bpFreqLo, \bpFreqHi), \bpFreqD), + \bpRQ, PL(\bpRQ), + \bpWet, PL(\bpWet), + + \amp, PL(\amp), + \panMax, PLseq([-1,1]) * PL(\panMax), + \out, 0 +); + +VarGui([ + \posLo, [0.0, 0.99, \lin, 0.01, 0.21], + \posHi, [0.0, 0.99, \lin, 0.01, 0.47], + \posRate, [0.1, 2, \lin, 0.01, 0.2], + \posDev, [0, 0.2, 5, 0, 0.002], + + \trigRateLo, [1, 200, \lin, 0.01, 21], + \trigRateHi, [1, 200, \lin, 0.01, 155], + \trigRateD, [0, 7, \lin, 1, 6], + + \granDurLo, [0.01, 0.6, \exp, 0.0, 0.037], + \granDurHi, [0.01, 0.6, \exp, 0.0, 0.4], + \granDurD, [0, 7, \lin, 1, 6], + + \rateLo, [0.1, 3, \lin, 0.01, 1.09], + \rateHi, [0.1, 3, \lin, 0.01, 1.63], + \rateD, [0, 7, \lin, 1, 1], + + \bpFreqLo, [50, 10000, \exp, 0.1, 54], + \bpFreqHi, [50, 10000, \exp, 0.1,8275], + \bpFreqD, [0, 7, \lin, 1, 1], + \bpRQ, [0.01, 0.99, \lin, 0.0, 0.07], + \bpWet, [0.0, 1, \linear, 0.0, 0.23], + + \panMax, [0.0, 1, \lin, 0.0, 0.85], + \amp, [0.0, 1, \lin, 0.01, 0.25] + ], stream: p +).gui(varColorGroups: (0..19).clumps([4,3,3,3,5,1,1])) +) + +:: + +anchor::Ex.2c:: +subsection::Ex.2c: Generating granular phrases with Pspawner + +code:: + +// This example needs SynthDef \gran_2b and Function d to be taken from Ex. 2b + +( +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +w = Buffer.sendCollection(s, Signal.hanningWindow(1024)); +) + +// A simple form of Pspawner is used to generate phrases. +// Phrase length params are taken a bit roughly as sustain and +// rest times also depend on randomly varying grain lengths. +// spSustain controls medium sustain time (without grain length overhead) +// spLegato controls medium legato factor (disregarding reduction by grain length overhead) +// spDev is causing separate random deviation of spSustain and spLegato +// between 1/(1+spDev) and 1+spDev + +// random distribution switching is restricted here to +// types 6 and 7 (random walks of first and second order) +// to force individual sound qualities of phrases. + +( +// declare var here as pattern is repeatedly evaluated from within the Pspawner, +// interpreter variable would be unsafe if running examples in parallel + +var p = Pbind( + \instrument, \gran_2b, + \sndBuf, b, + \windowBuf, w, + + \dur, 1 / PLswitch1(d.(\trigRateLo, \trigRateHi), \trigRateD), + \granDur, PLswitch1(d.(\granDurLo, \granDurHi), \granDurD), + \time, Ptime(), + \posRate, PL(\posRate), + + // random timeOffset added with each spawning + \pos, Pfunc { |e| + var relTime = ~posRate * e.time / e.sndBuf.duration + e.timeOffset, relDif; + relDif = ~posHi - ~posLo; + relTime + rand2(~posDev) % relDif + ~posLo; + }, + \rate, PLswitch1(d.(\rateLo, \rateHi), \rateD), + \bpFreq, PLswitch1(d.(\bpFreqLo, \bpFreqHi), \bpFreqD), + \bpRQ, PL(\bpRQ), + \bpWet, PL(\bpWet), + + \amp, PL(\amp), + \panMax, PLseq([-1,1]) * PL(\panMax), + \out, 0 +); + +q = Pspawner({ |sp| + var randomizer = { |x| var y = rand(x); 0.5.coin.if { 1 + y }{ 1 / (1 + y) } }, + sus, legato, delta; + + loop { + sus = ~spSustain * randomizer.(~spDev); + legato = ~spLegato * randomizer.(~spDev); + + // take random offset for each phrase + sp.par(Pfindur(sus, Psetpre(\timeOffset, 5.0.rand, p))); + delta = sus / (~spLegato * randomizer.(~spDev)); + sp.wait(delta) + } +}); + +VarGui([ + \posLo, [0.0, 0.99, \lin, 0.01, 0.16], + \posHi, [0.0, 0.99, \lin, 0.01, 0.41], + \posRate, [0.1, 2, \lin, 0.01, 1.4], + \posDev, [0, 0.2, 5, 0, 0.0017], + + \trigRateLo, [1, 200, \lin, 0.01, 70], + \trigRateHi, [1, 200, \lin, 0.01, 150], + \trigRateD, [6, 7, \lin, 1, 7], + + \granDurLo, [0.01, 0.6, \exp, 0.0, 0.02], + \granDurHi, [0.01, 0.6, \exp, 0.0, 0.11], + \granDurD, [6, 7, \lin, 1, 6], + + \rateLo, [0.1, 3, \lin, 0.01, 0.2], + \rateHi, [0.1, 3, \lin, 0.01, 1.86], + \rateD, [6, 7, \lin, 1, 7], + + \bpFreqLo, [50, 10000, \exp, 0.1, 67], + \bpFreqHi, [50, 10000, \exp, 0.1, 5885], + \bpFreqD, [6, 7, \lin, 1, 6], + \bpRQ, [0.01, 0.99, \lin, 0.0, 0.17], + \bpWet, [0.0, 1, \linear, 0.0, 0.38], + + \spSustain, [0.2, 2, \linear, 0.0, 0.884], + \spLegato, [0.6, 1.2, \linear, 0.0, 0.996], + \spDev, [0.0, 1, \linear, 0.0, 0.41], + + \panMax, [0.0, 1, \lin, 0.0, 0.85], + \amp, [0.0, 1, \lin, 0.01, 0.35] + ], stream: q +).gui(varColorGroups: (0..22).clumps([4,3,3,3,5,3,1,1]) ) +) + +:: +anchor::Ex.2d:: +subsection::Ex.2d: Wave sets + +code:: + +// For this example you need Alberto de Campo's Wavesets class +// (Quark extension, implementation following definitions of Trevor Wishart) +// and the Function d from Ex.2b. + +// the wave set player synth optionally adds a BPF applied to the signal, +// amount can be controlled with bpWet +// attack and release time > 0 for smoothening + +( +SynthDef(\wsPlayer, { arg out = 0, buf = 0, start = 0, length = 441, + rate = 1, att = 0.03, rel = 0.03, wvDur = 1, panMax = 0, amp = 0.2, + delayL = 0.0, delayR = 0.0, bpFreq = 500, bpRQ = 0.5, bpWet = 1; + var phasor, env, granSrc, src, attEff, relEff, sus; + + phasor = Phasor.ar(0, BufRateScale.ir(buf) * rate, 0, length) + start; + attEff = min(att, wvDur/2); + relEff = min(rel, wvDur/2); + sus = wvDur - attEff - relEff; + + env = EnvGen.ar(Env([0, 1, 1, 0], [attEff, sus, relEff], \sine), doneAction: 2); + granSrc = BufRd.ar(1, buf, phasor); + src = (BPF.ar(granSrc, bpFreq, bpRQ, mul: (bpRQ ** -1) * (400 / bpFreq ** 0.5)) * + bpWet + (granSrc * (1 - bpWet))); + OffsetOut.ar(out, Pan2.ar(src, panMax, amp) * env); +}).add; + +a = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +b = Buffer.read(s, a); +w = Wavesets.from(a); + +// relative positions of zero crossings +x = w.fracXings.drop(-1) / w.numFrames; +) + + +// Note that trigRate / event duration is not controlled directly in this setup, +// it's derived from wave set length (may vary) and legato factor. +// For short wave sets and a low legato value durs could become so short that +// a sudden mass of grains could cause hangs. +// To avoid this a parameter maxTrigRate is invented. + +// As wavesets start at distinguished positions in the buffer and +// - together with legato - durations are determined, +// an additionally given position rate in general cannot result in a "correct" +// looping through the buffer, there will be a deviation. +// Here two types of approximation can be choosen with posType: +// Type 0 takes the waveset nearest to the calculated exact position. +// Type 1 linearly maps positions to wave set indices. +// As wave sets are of different length the latter is a rough heuristic +// accelerating buffer parts with relatively low frequencies. + +( +p = Pbind( + \instrument, \wsPlayer, + + // refering to interpreter variables within Pfuncs + // when running several examples in parallel is unsafe, + // so pass them here, then access from within the event + + \b, b, + \w, w, + \x, x, + + \time, Ptime(), + \posLo, PL(\posLo), + \posHi, PL(\posHi), + \posRate, PL(\posRate), + + \pos, Pfunc { |e| (e.time * e.posRate / e.b.duration) % + (e.posHi - e.posLo) + e.posLo }, + + // Estimation of ws index from relative position, see explanation above, + // indexIn might be a bottleneck with large buffers, + // also a more rough estimation of ws index could be used: + // \startWs, Pfunc { |e| e.pos.linlin(0, 1, 0, e.w.xings.size - 2).round.asInteger } + + \startWs, Pfunc { |e| + (~posType == 0).if { + e.x.indexIn(e.pos) + }{ + e.pos.linlin(e.posLo, e.posHi, e.x.indexIn(e.posLo), e.x.indexIn(e.posHi)) + .round.asInteger + } + }, + + \numWs, PLswitch1(d.(\numWsLo, \numWsHi), \numWsD), + \repeats, PLswitch1(d.(\repeatsLo, \repeatsHi), \repeatsD), + + \bpFreq, PLswitch1(d.(\bpFreqLo, \bpFreqHi), \bpFreqD), + \bpRQ, PL(\bpRQ), + \bpWet, PL(\bpWet), + + \rate, PLswitch1(d.(\rateLo, \rateHi), \rateD), + \data, Pfunc { |e| e.w.frameFor(e.startWs, e.numWs) }, + + \buf, b.bufnum, + \start, Pkey(\data).collect(_[0]), // startFrame + \length, Pkey(\data).collect(_[1]), // length (frameNum) + \wvDur, Pkey(\data).collect(_[2]) * Pkey(\repeats), // sustain time + + \calculatedDur, Pkey(\wvDur) / PLswitch1(d.(\legatoLo, \legatoHi), \legatoD), + \dur, Pfunc { |e| max(e.calculatedDur, 1 / ~maxTrigRate) }, + + \panMax, PLseq([-1,1]) * PL(\panMax), + \amp, PL(\amp), + \out, 0 +); + + +VarGui([ + \posLo, [0, 1, \lin, 0.0, 0.15], + \posHi, [0, 1, \lin, 0.0, 0.45], + \posRate, [0.0, 2, \lin, 0.01, 0.25], + \posType, [0, 1, \lin, 1, 0], + + \numWsLo, [1, 100, \lin, 1, 5], + \numWsHi, [1, 100, \lin, 1, 23], + \numWsD, [0, 7, \lin, 1, 6], + + \repeatsLo, [1, 4, \lin, 1, 1], + \repeatsHi, [1, 4, \lin, 1, 2], + \repeatsD, [0, 7, \lin, 1, 6], + + \maxTrigRate, [1, 250, \lin, 1, 200], + + \bpFreqLo, [50, 10000, \exp, 0.1, 67], + \bpFreqHi, [50, 10000, \exp, 0.1, 9600], + \bpFreqD, [0, 7, \lin, 1, 7], + \bpRQ, [0.01, 0.99, \lin, 0.005, 0.22], + \bpWet, [0.0, 1, \lin, 0.005, 0.0], + + \rateLo, [0.05, 2, \lin, 0.0, 0.32], + \rateHi, [0.05, 2, \lin, 0.0, 1.3], + \rateD, [0, 7, \lin, 1, 7], + + \att, [0.0, 0.05, \lin, 0.001, 0.001], + \rel, [0.0, 0.05, \lin, 0.001, 0.001], + + \panMax, [0.0, 1, \lin, 0, 0.8], + \legatoLo, [0.3, 25, \exp, 0, 0.4], + \legatoHi, [0.3, 25, \exp, 0, 5.5], + \legatoD, [0, 7, \lin, 1, 7], + \amp, [0.0, 2.0, \lin, 0.0, 0.7] + ], + stream: p +).gui(varColorGroups: (0..25).clumps([4,3,3,1,5,3,2,1,3,1])) +) + + +:: + + +anchor::3:: +SECTION::3. Hybrid Implementations + +subsection::Ex.3a: Granulation with ugen plus step sequencing + +code:: + +// Here the trigger for the TGrains ugen comes from a Pbind +// which also generates rates like a step sequencer + + +( +SynthDef(\gran_3a, { arg out = 0, posLo = 0.0, posHi = 1.0, + posRate = 1, posDev = 0.01, bufNum = 0, t_trig = 0, + granDur = 0.1, t_rate = 1.0, rateDev = 0, + panMax = 1, amp = 0.1, interp = 4; + + var pan, pos, bufDur, bufDurSection, posDif; + + posDif = posHi - posLo; + bufDur = BufDur.kr(bufNum); + bufDurSection = bufDur * posDif; + pos = posLo * bufDur + + (Phasor.ar(0, BufRateScale.kr(bufNum) * posRate / SampleRate.ir, posLo * bufDur, posHi * bufDur) + + (TRand.kr(-0.5, 0.5, t_trig) * posDev * bufDur)).mod(bufDurSection); + pan = Demand.kr(t_trig, 0, Dseq([panMax, panMax.neg], inf) * 0.999); + Out.ar(out, TGrains.ar(2, t_trig, bufNum, t_rate, pos, granDur, pan, 1, interp) * amp); + }, metadata: ( + specs: ( + posLo: [0.01, 0.99, \lin, 0.01, 0], + posHi: [0.01, 0.99, \lin, 0.01, 1], + posRate: [0.1, 2, \lin, 0.01, 1], + posDev: [0, 0.2, 5, 0, 0.01], + panMax: [0.0, 1, \lin, 0.005, 0.8], + amp: [0.0, 1, \lin, 0.005, 0.5] + ) + ) +).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. +) + + +// As the setting Pbind needs to know the Synth's nodeID +// the Synth has to be started explicitely and passed to the VarGui later on +// (VarGui takes Synths as well as SynthDefs, passing a SynthDef is recommended in general). +// The Synth starts silently as t_trig defaults to 0. + + +( +x = Synth(\gran_3a, [\bufNum, b]).register; + +p = Pbind( + \type, \set, + \id, x, + \args, [\t_trig, \t_rate, \granDur], + + \dur, PL(\dur), + \granDur, Pkey(\dur) * PL(\legato), + \t_trig, 1, + \t_rate, PLseq(\midi).midiratio +); +) + +// Do start and pause with the Pbind (EventStreamPlayer) player. +// If you stop the Synth you cannot resume audio with a new Synth +// as the EventStreamPlayer has lost the correct nodeID +// (however the Synth can be paused and resumed). + +( +VarGui(varCtr: [ + \dur, [0.01, 0.1, \lin, 0, 0.05], + \legato, [0.3, 3, \lin, 0, 1], + \midi, [-12, 12, \lin, 1, 1] ! 8 + ], synth: x, stream: p +).gui; +) + +:: + + +subsection::Ex.3b: Using external control synths + +code:: + +// Example needs SynthDef from Ex.2a + +// Also with language-driven granulation +// controls can be delegated to separate Synths, +// which output to control buses. +// Control inputs of single synths can read from +// these buses (comfortably use aBus.asMap in the Pbind) +// or synths can read from buses with In.kr (needs extra definition). + +// A nearby parameter to determine with a separate synth is grain position + +( +SynthDef(\bufPhasor, { |out = 0, sndBuf = 0, posRate = 1, posLo = 0, posHi = 1, posDev = 0.01| + var pos, posDif; + posDif = posHi - posLo; + pos = Phasor.ar(1, posRate * BufRateScale.kr(sndBuf) / BufFrames.kr(sndBuf), 0, posDif) + + WhiteNoise.kr(posDev / 2) % posDif + posLo; + Out.kr(out, A2K.kr(pos)); + } +).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +w = Buffer.sendCollection(s, Signal.hanningWindow(1024)); +c = Bus.control(s,1); +) + +// in GUI start EventStreamPlayer and bufPhasor Synth + +( +p = Pbind( + \instrument, \gran_2a, + \sndBuf, b, + \windowBuf, w, + + \dur, 1 / PL(\trigRate), + \granDur, PL(\granDur), + + \pos, c.asMap, + \rate, PL(\rate), + \amp, PL(\amp), + \panMax, PLseq([-1,1]) * PL(\panMax), + \out, 0 +); + +VarGui([ + \trigRate, [1, 200, \lin, 0.01, 50], + \granDur, [0.01, 0.3, \lin, 0.005, 0.12], + \rate, [0.1, 3, \lin, 0.01, 1], + \panMax, [0.0, 1, \lin, 0.0, 0.8], + \amp, [0.0, 1, \lin, 0.01, 0.3] + ],[ + \out, c.index, + \sndBuf, b.bufnum, + \posLo, [0, 1, \linear, 0.005, 0], + \posHi, [0, 1, \linear, 0.005, 1], + \posRate, [0.1, 2, \linear, 0.01, 1], + \posDev, [0, 0.2, 5, 0, 0.01] + ], + p, \bufPhasor +).gui(sliderPriority: \synth, playerPriority: \synth); +) + + +:: + + +subsection::Ex.3c: Switching between ugens of external control synths + +code:: + +// Example needs SynthDef from Ex.2a + +// external control synth for position as in Ex.3a, but with +// different types of movement to select + +( +SynthDef(\bufPosLFO, { |out = 0, lfoType = 0, freq = 1, posLo = 0, posHi = 1, posDev = 0.01| + var pos, posDif; + posDif = posHi - posLo; + pos = WhiteNoise.kr(posDev / 2) + Select.kr(lfoType, + [LFDNoise0, LFDNoise1, LFDNoise3].collect(_.kr(freq, posDif))) % posDif + posLo; + Out.kr(out, pos); +}).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +w = Buffer.sendCollection(s, Signal.hanningWindow(1024)); +c = Bus.control(s,1); +) + + +// added parallel grains +// in GUI start bufPhasor Synth before or together with EventStreamPlayer + +// buffer position movement can be forward and backward +// lfoType 0: LFDNoise0 (jumps) +// lfoType 1: LFDNoise1 (linear interpolation) +// lfoType 2: LFDNoise3 (cubic interpolation, smooth, useful in many control contexts) + +( +p = Pbind( + \instrument, \gran_2a, + \sndBuf, b, + \windowBuf, w, + + \dur, 1 / PL(\trigRate), + \granDur, PL(\granDur), + + \pos, c.asMap, + \rate, PL(\rate) * PL(\midiAdd).midiratio, + \amp, PL(\amp), + \panMax, PLseq([-1,1]) * PL(\panMax), + \out, 0 +); + +VarGui([ + \trigRate, [1, 200, \lin, 0.01, 80], + \granDur, [0.01, 0.3, \lin, 0.005, 0.195], + \rate, [0.1, 1.5, \lin, 0.01, 0.6], + \midiAdd, [-5, 0].collect([-12, 12, \lin, 1, _]), + \panMax, [0.0, 1, \lin, 0.0, 0.95], + \amp, [0.0, 1, \lin, 0.01, 0.15] + ],[ + \out, c.index, + \posLo, [0, 1, \linear, 0.005, 0.15], + \posHi, [0, 1, \linear, 0.005, 0.43], + \posDev, [0, 0.2, 5, 0, 0.0], + \freq, [0.01, 2, \lin, 0, 0.96], + \lfoType, [0, 2, \lin, 1, 2] + ], + p, \bufPosLFO +).gui(sliderPriority: \synth, playerPriority: \synth); +) + +:: + + +subsection::Ex.3d: Pattern-driven sequencing of granular events using demand rate ugens + +code:: + +// This is basically the same as SynthDef \gran_1d with an additional envelope, +// grain position phasor is left out, position is determined by a phasor synth via bus and mapping. + +( +// length of demand rate sequence, you might want to check larger sizes +// in connection with gui arg tryColumnNum > 1 +~n = 5; + + +SynthDef(\gran_3d, { |out = 0, soundBuf, envBuf, att = 0.1, sus = 1, rel = 1, pos = 0.5, + granDurMul = 1, rateMul = 1, overlapMul = 1, panMul = 1, amp = 0.5, interp = 2| + + var signal, bufDur, granDur, granGate, relGranDurs, overlap, relOverlaps, overlapSeq, + pan, rate, relRates, rateSeq, granDurSeq; + + // array args for demand rate sequencing, short form of NamedControl + relGranDurs = \relGranDurs.kr(0.1!~n); + relRates = \relRates.kr(1!~n); + relOverlaps = \relOverlaps.kr(1!~n); + + // Dstutter (or Dunique) necessary as granDurSeq is polled twice: granGate and granDur + granDurSeq = Dstutter(2, Dseq(relGranDurs, inf)); + rateSeq = Dseq(relRates, inf); + overlapSeq = Dseq(relOverlaps, inf); + + granGate = TDuty.ar(granDurSeq * granDurMul); + granDur = Demand.ar(granGate, 0, granDurSeq * granDurMul); + rate = Demand.ar(granGate, 0, rateSeq) * rateMul; + pan = Demand.ar(granGate, 0, Dseq([1, -1], inf)) * 0.999 * panMul; + overlap = Demand.ar(granGate, 0, overlapSeq) * overlapMul; + + bufDur = BufDur.kr(soundBuf); + signal = TGrains.ar(2, granGate, soundBuf, rate, pos * bufDur, granDur * overlap, pan, 1, interp) * + EnvGen.kr(Env([0, 1, 1, 0], [att, sus, rel]), doneAction: 2); + + Out.ar(out, signal * amp); +} +).add; + +SynthDef(\bufPhasor_2, { |out = 0, sndBuf = 0, posRateE = 0, posRateM = 1, + posLo = 0, posHi = 1, posDev = 0.01| + + var pos, posDif, posRate; + posDif = posHi - posLo; + posRate = 10 ** posRateE * posRateM; + pos = Phasor.ar(1, posRate * BufRateScale.kr(sndBuf) / BufFrames.kr(sndBuf), 0, posDif) + + WhiteNoise.kr(posDev / 2) % posDif + posLo; + Out.kr(out, A2K.kr(pos)); +} +).add; + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + +c = Bus.control(s,1); +) + + +// Pattern control of granular events + +// Every granular event gets a duration between durLo and durHi (exp distribution) +// and an envelope according to att, sus and rel. +// One of four events is randomly defined as rest. + +// arg arrays relGranDurs, relRates and relOverlaps determine +// demand rate sequencing for granulation as in Ex. 1d. +// Per event they are multiplied with corresponding factors +// limited by granDurMulLo/Hi, rateMulLo/Hi and overlapMulLo/Hi + +// start phasor synth (first row in player console) before event stream player +// event stream player might start with rest + + +( +// Passing arrayed args with an event pattern requires +// wrapping them into an array or Ref object. +// This is necessary to distinguish from triggering +// several synths per event. +// .collect(`_) is short for .collect { |x| Ref(x) } +// .collect([_]) or .collect { |x| [x] } would also be possible + +p = Pbind( + \instrument, \gran_3d, + \soundBuf, b, + \pos, c.asMap, + + \dur, PLexprand(\durLo, \durHi), + \type, PLshufn(\note!3 ++ \rest), + \att, PL(\att), + \sus, PL(\sus), + \rel, PL(\rel), + + + \relGranDurs, PL(\relGranDurs).collect(`_), + \granDurMul, PLwhite(\granDurMulLo, \granDurMulHi), + + \relOverlaps, PL(\relOverlaps).collect(`_), + \overlapMul, PLwhite(\overlapMulLo, \overlapMulHi), + + \relRates, PL(\relRates).collect(`_), + \rateMul, PLwhite(\rateMulLo, \rateMulHi), + + \panMul, PL(\panMul), + \amp, PL(\amp) +); + +VarGui([ + \durLo, [0.05, 1.5, \lin, 0, 0.16], + \durHi, [0.05, 1.5, \lin, 0, 1.2], + \att, [0.01, 0.6, \lin, 0, 0.4], + \sus, [0.01, 0.6, \lin, 0, 0.05], + \rel, [0.01, 0.6, \lin, 0, 0.5], + \relGranDurs, { |i| [0.01, 0.1, \lin, 0, i * 0.005 + 0.02] } ! ~n, + \granDurMulLo, [0.03, 2, \lin, 0, 0.05], + \granDurMulHi, [0.03, 2, \lin, 0, 1.8], + + \relRates, { |i| [0.1, 1.5, \lin, 0, (5-i) * 0.1 + 0.5] } ! ~n, + \rateMulLo, [0.1, 2, \lin, 0, 0.5], + \rateMulHi, [0.1, 2, \lin, 0, 1.5], + + \relOverlaps, [0.5, 3, \lin, 0, 2] ! ~n, + \overlapMulLo, [0.1, 2, \lin, 0, 0.25], + \overlapMulHi, [0.1, 2, \lin, 0, 1.8], + + \panMul, [0.0, 1, \lin, 0.0, 0.8], + \amp, [0.0, 3, \lin, 0.01, 1.8] + ],[ + \out, c.index, + \sndBuf, b.bufnum, + \posLo, [0, 1, \lin, 0.005, 0.1], + \posHi, [0, 1, \lin, 0.005, 0.9], + \posRateE, [-3, 4, \lin, -1, 0], + \posRateM, [0.1, 10, \exp, 0.01, 1], + \posDev, [0, 0.2, 5, 0, 0.01] + ], + p, \bufPhasor_2 +).gui( + tryColumnNum: 2, + sliderPriority: \synth, + playerPriority: \synth, + varColorGroups: (0..(~n*3+12)).clumps([2,3,~n+2,~n+2,~n+2,1,1]), + synthColorGroups: (0..6).clumps([1,1,2,2,1]), + labelWidth: 90, + sliderWidth: 300 +); +) + +:: + + +anchor::4. Extensions of Setups:: +SECTION::4. Extensions of Setups + + +list:: +## strong::Changing ranges and scaling:: + +This concerns all control parameters in question. E.g. the layering of long grains (> 200 ms) in connection with small rates of position changes (posRate) often has interesting effects. One may want to drop the term granulation in that case, though it's the same structure of synthesis. For such parameters with a very large coefficient boundHi / boundLo one may take exponential scaling, and if this is not fine enough you can invent a control pair of mantissa and exponent (as for posRate in link::#Ex.1b::). +:: + +list:: +## strong::Parameter linkage:: + +On the one hand a logical restriction, on the other hand it can make sense from a musical / perceptional point of view. E.g. shortening of grains could be linked with a raise of rate (as low frequencies might fail to unfold in short grains). Anyway parameter linkage is reducing complexity - it's a trade-off between simplicity of the interface and exclusion of certain constellations which should be considered from case to case. +:: + +list:: +## strong::Inventing and extending controls and LFO changes dependant on specific buffers and parameter sets:: + +Say one has started playing around with a certain buffer and a general granulation patch. A parameter set that gives an interesting sound may react in a very interesting way on a change of a single parameter e.g., trigger rate. Then it may be an option to build in a control or a LFO specifically designed for that parameter - LFO is meant here in a general sense, it could be a LFO in a Synth, a dedicated LFO synth or defined by a rapidly sequencing Pattern. +:: + +list:: +## strong::Iterated granulation:: + +Granulation of buffers themselves resulting from buffer granulation can give interesting effects. +:: + +list:: +## strong::Spatialization:: + +For the sake of ease and comparison a L/R-switch per grain with one panning parameter was used in the examples above. Needless to say that spatial scattering of grains remains a large field of experimentation. Generally spoken spatialization can be part of the synthesis process or carried through independently afterwards, but also a combination of both approaches is feasible. +:: + +list:: +## strong::Effects:: + +Effect processing can be applied to all or single grains in a language-driven granulation setup. There can be one or more effects, serial or in parallel, defined outside or inside the Synth playing the buffer, as with the BPF in link::#Ex.2b::, link::#Ex.2c::, link::#Ex.2d::. In these examples the bandpass is applied in general, but also a sequencing of effects can be done. And even in the case of just one effect (e.g. reverb) a decent sequencing of Fx- / noFx-events can sound very interesting. This can be done with PbindFx (as in the project link::Tutorials/kitchen_studies::), sequencing not more than one effect per grain can be done straightly: continously running effect synths read from different buses and events with different out values cause the player synths to output to these buses. +:: + +list:: +## strong::Micro rhythm:: + +See Xenakis' suggestion of Sieves with rhythm generation as a special application, a granulation example is contained in the example section of: link::Tutorials/Sieves_and_Psieve_patterns::. PSPdiv, a dynamic multi-layer pulse divider, which is based on Pspawner, can also be used in this context, see the last example of link::Classes/PSPdiv::. +:: diff --git a/HelpSource/Tutorials/DX_suite.schelp b/HelpSource/Tutorials/DX_suite.schelp new file mode 100644 index 0000000..b5d442c --- /dev/null +++ b/HelpSource/Tutorials/DX_suite.schelp @@ -0,0 +1,156 @@ +TITLE::DX suite +summary::pseudo ugens for crossfaded mixing and fanning according to demand-rate control +categories:: Libraries>miSCellaneous>DX suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/PbindFx, Tutorials/kitchen_studies + + +DESCRIPTION:: + +DX (Demand XFade) ugens are built upon DemandEnvGen and PanAz and can hence use their dynamic control options. Their user interface and underlying ugen structure is almost identical, due to multichannel expansion they are capable of triggering complex signal flows. As demand rate sequencing can be performed fast, DX ugens can, beneath their functionality as signal distribution controllers in the medium or large time-scale, be used as genuin synthesis tools in the area of microsound, e.g. for fast switching between sources as well as different processings of them. DXEnvFan and DXEnvFanOut give specific options as they can be used as multichannel envelopes and triggers at the same time. This e.g. enables server-side granulation techniques for arbitrary sound sources that are difficult to handle with granulation ugens alone, such es effect sequencing per grain and others. A related application, not necessarily in a granular time-scale, is crossfaded playback from different buffer positions. Finally DX fanning ugens allow server-side definition of spatial movements by crossfading between non-adjacent channels respectively buses. + + +note:: +As interface and conventions of DX ugens are nearly identical, I didn't double examples for all features. It's recommended to start with the DX suite overview and go through the help file examples in this order: link::Classes/DXMix#Ex.1#DXMix:: - link::Classes/DXMixIn#Ex.1#DXMixIn:: - link::Classes/DXEnvFan#Ex.1#DXEnvFan:: - link::Classes/DXEnvFanOut#Ex.1#DXEnvFanOut:: - link::Classes/DXFan#Ex.1#DXFan:: - link::Classes/DXFanOut#Ex.1#DXFanOut::. Some general conventions are treated in detail in the following examples: fades and steps in link::Classes/DXMix#Ex.2#DXMix, Ex.2:: – width and offset arguments in link::Classes/DXMix#Ex.3#DXMix, Ex.3:: – multichannel expansion in link::Classes/DXMix#Ex.6#DXMix, Ex.6:: – crossfade types in link::Classes/DXEnvFan#Ex.1#DXEnvFan, Ex.1::. +:: + +note:: +PanAz.ar's args pos and orientation were scaled wrongly in SC versions up to 3.8. DX ugens neutralize this bug by inverse scaling, so it should actually work the same with SC versions before 3.9 with the exception of examples with modulatable width (disabled in earlier versions). I didn't encounter differences in any other test examples, however I'd rather recommend a SC version from 3.9 onwards, if you have the choice. +:: + +note:: +Depending on the multichannel sizes it might be necessary to increase server resources, i.e. the number of interconnect buffers (e.g. s.options.numWireBufs = 256; s.reboot). See link::Classes/DXMix#Ex.8#DXMix, Ex.8:: and link::Classes/DXEnvFan#Ex.2#DXEnvFan, Ex.2::, link::Classes/DXEnvFan#Ex.4#DXEnvFan, Ex.4:: for aspects of CPU demand. +:: + +note:: +In my tests timing was exact up to one sample. So when used for granulation DX ugens avoid the inevitable inccuracies of language-based triggering in realtime. However care has to be taken: fade and step times must be larger than the duration of a control cycle. With default values sampleRate = 44100 Hz and blockSize = 64, this equals ca. 0.00145 sec. If you go below, the fade mechanism is messed up and you get jumps and clicks. Accordingly with fadeModes 3 and 4 you have to ensure that the remaining 'real' stepTime, which is calculated by stepTime minus fadeTime, is larger than this threshold. But as a workaround you can always lower the blocksize. See link::Classes/DXFan#Ex.4#DXFan, Ex.4:: for aspects of granulation with high trigger rates / short grain durations. +:: + +note:: +The current implementation is bound to counting with Dseries and – inherent to 32 bit floats – the integer accuracy limit of 2 ** 24 - 1 = 16777215. This can be an issue with setups that are using extreme short durations for hours. +:: + + +subsection::Credits +Thanks to Wouter Snoei for his PlayBufCF class. It gave me a lot of inspiration for DX ugens – although in the end the implementation with PanAz and DemandEnvGen is quite different. Thanks also to Till Bovermann for ironing out a longstanding bug in PanAz. + + + + +SECTION::Examples + +anchor::Ex.1:: +subsection::Ex.1 DXMix, crossfade sequencing + +code:: +// Crossfaded switching between sources, there exists a number of options, +// e.g. for fade mode (inclusion of steps = plateau phases), curve type and width. +// The syntax of passing the sources within a Ref object is necessary +// to distinguish from multichannel expansion. + +( +{ + DXMix.ar( + Dseq([1, 0, 1, 2], inf), + `([SinOsc.ar(100), WhiteNoise.ar(), LFTri.ar(100)]), + stepTime: 0.015, + fadeTime: 0.015, + fadeMode: 1, // alternate steps and fades + sine: 0, // sine type or not + equalPower: 0 // square-rooted (equal power) or not + ) +}.plot(0.12) +) +:: + + +anchor::Ex.2:: +subsection::Ex.2 Comparison of fanning DX ugens + +code:: +// Crossfading source signals with DXFan, +// result is a multichannel signal of size that has to be passed + +( +{ + DXFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + SinOsc.ar(500), + size: 8, + fadeTime: 0.01 + ) +}.plot(0.1) +) + +( +{ + DXFan.ar( + Dseq([2, 0, 4, 6], inf), + `(SinOsc.ar([300, 700])), + size: 8, + fadeTime: 0.01 + ) +}.plot(0.1) +) + + +// DXEnvFan returns a multichannel envelope, +// the size has to be passed. +// Without any options it defaults to the square-rooted (equal power) sine type. + +( +{ + DXEnvFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + size: 8, + fadeTime: 0.01, + ) +}.plot(0.1) +) + +// proof of concept with other fanning DX ugens: + +// for getting the same result with DXFan pass a DC as source +( +{ + DXFan.ar( + Dseq([3,2,1,4,5,6,7,0], inf), + DC.ar(1), + size: 8, + fadeTime: 0.01 + ) +}.plot(0.1) +) + +// envelopes can also be sent to buses, for plotting we can get them back with In, +// here the size is considered via the bus. + +( +a = Bus.audio(s, 8); +{ + DXEnvFanOut.ar( + Dseq([3,2,1,4,5,6,7,0], inf) + a.index, + fadeTime: 0.01 + ); + In.ar(a, 8) +}.plot(0.1) +) + +// analogously with DXFanOut and DC input + +( +b = Bus.audio(s, 8); +{ + DXFanOut.ar( + Dseq([3,2,1,4,5,6,7,0], inf) + b.index, + DC.ar(1), + fadeTime: 0.01 + ); + In.ar(b, 8) +}.plot(0.1) +) + +( +a.free; +b.free; +) +:: diff --git a/HelpSource/Tutorials/Event_patterns_and_Functions.schelp b/HelpSource/Tutorials/Event_patterns_and_Functions.schelp new file mode 100644 index 0000000..d256ede --- /dev/null +++ b/HelpSource/Tutorials/Event_patterns_and_Functions.schelp @@ -0,0 +1,320 @@ + + +TITLE::Event patterns and Functions +summary::using event patterns with functional elements +categories:: Libraries>miSCellaneous>General Tutorials, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/PLx_suite, Classes/VarGui, Tutorials/VarGui_shortcut_builds + +DESCRIPTION:: + +This is a tutorial file about event patterns with functional code. Features concerning scope are regarded along a line from Functions to Streams, Streams of Events and EventStreamPlayers. These general characteristics allow to generate a parametrized family of EventStreamPlayers from a single event pattern definition and are used as a base for controlling EventStreamPlayers with link::Classes/VarGui:: . For a convenience way to generate Patterns with environment-dependent reference see link::Tutorials/PLx_suite:: . + + +SECTION::Functions in Environments + +Environments are a standard way to separate namespaces in SuperCollider. Functions may include strong::environmental variables:: and then strong::dynamic scope:: comes into play: variables get the value from the context in which the Function is strong::evaluated::. Anyway a specific environment can be linked with the Function, the latter will hold for Streams polled from Patterns with certain functional code - it's just the environment in which the stream has been generated from the pattern. + +Take a simple Function with one argument and assign it to the strong::interpreter variable:: f: + +code:: + +f = { |x| x*2 + ~a }; + +// equivalent: + +f = { |x| x*2 + currentEnvironment[\a] }; + +// now set the variable in the Environment (context) in which to evaluate the Function later on + +~a = 1; + +// equivalent: +// currentEnvironment[\a] = 1; + +// not surprising the result of the following operation: + +f.value(1); + +// or shorter: +// f.(1) + +-> 3 + +// now evaluation in new environment, value taken from there: + +( +e = Environment[\a -> 5]; +e.use { f.value(1) }; +) + +-> 7 + +// with inEnvir a new Function is bound to a specific Environment + +( +g = f.inEnvir(e); +g.(1); +) + +-> 7 + + +f.(1); + +-> 3 + +:: + +So either by evaluating the original Function in different Environments or, equivalently, by deriving new Functions from the original attached to different Environments we create a parametrized family of Functions. The Function's basic behaviour is pretty simple (x*2), in dependance of the context it is just varied (a linear offset is added). With more environmental variables a much greater complexity could be introduced, though possibly obscuring the basic behaviour. + +This priciple can now easily be extended to Streams, Streams of Events and EventStreamPlayers. We define the basic behaviour of an event stream with an event pattern (Pbind), then enrich the event pattern with functional code and can have a huge variety of EventStreamPlayers in different Environments with different parameter sets - all playable and modifiable in realtime (in parallel or independentely) and all polled from one single event pattern definition! Step by step: + +SECTION::Streams in Environments + +What happens in the case of a Stream that will repeatedly evaluate a Function? + +code:: + +// the Pfunc just describes what a Stream, polled from it, should do (evaluate a Function by the method next) +// the Pfunc itself is not bound to a specific Environment + +p = Pfunc { ~a }; + +// by making a Stream an Environment (the current) is attached + +( +q = p.asStream; +~a = 1; +q.next; +) + +-> 1 + +// next value of (Func)Stream demanded in new Environment will be taken from old defining context + +( +~a = 2; +e = Environment[\a -> 5]; +e.use { q.next }; +) + +-> 2 + + +// vice versa Stream defined in new Environment takes next value from there +// also if evaluated in other Environment + +( +r = e.use { p.asStream }; +r.next; +) + + +-> 5 + +:: + +Indeed, Streams derived from the simple Pfunc don't do much here, they just reflect values in the Environment in which they are defined. As with Functions in the first example Pfuncs can be combined with other Patterns to modify their behaviour. So a family of related Streams (common attributes) can be polled from a single pattern. + + +code:: + +// try above with new pattern +// here the common attributes are: period length = 2, magnitude relation of items = 1:10) + +p = Pseq([1,10], inf) * Pfunc { ~a }; + +:: + +An even more generalized operation is the use of Pcollect, which defines the following Stream behaviour: Output of the source stream will be taken as input by the collecting stream, as with Pfunc the Function defined in Pcollect will live in the Environment in which the Stream has been polled from the Pattern. The above could also be written like this: + +code:: + +p = Pcollect({ |x| x * ~a }, Pseq([1,10], inf)); + +p = Pseq([1,10], inf).collect({ |x| x * ~a }); + +p = Pseq([1,10], inf).collect(_*~a); // short form (partial application), don't overrely on it in more complicated cases + +:: + +There is another Pattern engaging Functions, thus allowing to benefit from environment-dependance: Plazy. it evaluates a Function that returns a Pattern to be embedded in a stream. For repeated embedding the Plazy can be wrapped into a Pn. If a generated Pattern repeats infinitely, there will not be any further evaluation. So when using Plazy have a close look at the inner Pattern's repeat arg. + +code:: + +// with each evaluation of Plazy's Function a new random sequence of length = 2 will be generated and repeated 3 times +// maximum range of the whole sequence is controlled by the environmental variable ~a + +( +p = Pn(Plazy { Pseq({ rand2(~a) } ! 2, 3) }); +q = p.asStream; +~a = 3; +q.nextN(60); +) + +// instead of using an Environment we can use an instance of its subclass Event which has handy syntax. +// new empty Event: + +(); + +// new Event with var ~a set, range enlarged: + +( +e = (a: 10); +r = e.use { p.asStream }; +r.nextN(60); +) + +// compare, both streams are demanded values in same Environment, but they are attached to different ones + +q.nextN(60); + +:: + +This example was still similar to the ones before, basically a loop modified by a factor. But imagine that a Plazy could give out arbitrary new Patterns, the choice itself could depend on an environment-dependant parameter. + + +SECTION::Event streams in Environments + + +One step closer to the sound: let's define an event pattern with single patterns that contain functional code. Again the pattern itself is neutral concerning the relation to Environments ... + + +code:: + +( +p = Pbind( + \dur, Pfunc { ~a }, + \midinote, Pfunc { ~b } +); +) + +// ... but the stream is not neutral. It's bound to the current environment. + +( +q = p.asStream; + +~a = 0.5; +~b = 60; +) + +// define a new Environment - an Event, as syntax is handy. + +e = (a: 1, b: 70); + +// So we have two surrounding Events as variable spaces, in which Streams of Events can live. +// Don't be confused by that, the stream-generated Events are a different story. + +// now check a next element of the event stream in the new environment (event). +// The method next must itself be passed an event - +// the result stems from the former current event, in which the event stream was generated + +e.use { q.next(()) }; + +-> ( 'dur': 0.5, 'midinote': 60 ) + +// double check - also the second event stream belongs to its defining context + +( +e.use { r = p.asStream; }; +r.next(()); +) + +-> ( 'dur': 1, 'midinote': 70 ) + +:: + +SECTION::EventStreamPlayers in Environments + +Not much will change by the last transition, EventStreamPlayers are also attached to environments. + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +p = Pbind( + \dur, Pfunc { ~a }, + \midinote, Pfunc { ~b } +); +) + +// define two Environments (Events) with EventStreamPlayers attached to it + +( +e = (a: 0.2, b: 60); +f = (a: 0.4, b: 67); + +e.use { q = p.asEventStreamPlayer }; +f.use { r = p.asEventStreamPlayer }; +) + + +// play the players with different init data in sync + +( +q.play(quant: 0.2); +r.play(quant: 0.2); +) + + +// now change envir variables while playing +// the stream will take new values at the next evaluation + +f.b = 65; + +e.b = 62; + +( +q.stop; +r.stop; +) + +:: + +The VarGui interface can be used to control running EventStreamPlayers in that way. They may be passed directly, then their attached Environments will be taken for variable setting: + + +code:: + +// start playing from gui + +( +v = VarGui([[ + \a, [0.2, 0.8, \lin, 0.2, 0.2], + \b, [48, 80, \lin, 1, 58] + ],[ + \a, [0.2, 0.8, \lin, 0.2, 0.4], + \b, [48, 80, \lin, 1, 67] + ]], stream: [q, r], quant: 0.2 +).gui; +) + +// so you could still set from outside + +f.b = 65; + +:: + +But also the event pattern can be passed directly (recommended). Then new separate Environments will be generated automatically, +changing envir variables by accident is very unlikely. + +code:: + +( +v = VarGui({ [ + \a, [0.2, 0.8, \lin, 0.2, 0.2 * (4.rand + 1) ], + \b, [48, 80, \lin, 1, 48.rrand(80) ] + ] } ! 10, stream: p ! 10, quant: 0.2 +).gui(tryColumnNum: 2); +) + +// however, environments are accessible if necessary + +v.envirs; + +:: diff --git a/HelpSource/Tutorials/Event_patterns_and_LFOs.schelp b/HelpSource/Tutorials/Event_patterns_and_LFOs.schelp new file mode 100644 index 0000000..52f84db --- /dev/null +++ b/HelpSource/Tutorials/Event_patterns_and_LFOs.schelp @@ -0,0 +1,572 @@ + + +TITLE::Event patterns and LFOs +summary::summary of some LFO control strategies for event patterns +categories:: Libraries>miSCellaneous>General Tutorials, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Guides/Guide_to_HS_and_HSpar, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Tutorials/HS_with_VarGui + + +DESCRIPTION:: + +Basic distinction: synths generated by an event pattern can be controlled directly by a LFO (synths wired or mapped to control buses) or on a per-event base. The latter can be achieved by language-only strategies or with help of control synths. For the sake of clarity most examples use the default instrument and pitch as control parameter. + + + +SECTION::1. Control by new values per event + +anchor::Ex.1a:: +subsection::Ex.1a: Functions of time + +code:: + + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +( +// LFO defined as Function + +f = { |x| (x * 2).sin * 3 + (x * 0.3).sin }; + +p = Pbind( + \dev, Ptime().collect(f), // current time passed to function + \midinote, Pkey(\dev) + 60 + [0, 4], + \amp, 0.05, + \dur, 0.15 +).play; +) + +p.stop; + + +////////////////////////// + +// example with GUI + + +( +// parametric control function + +f = { |x| (x * ~a[0]).sin * ~b[0] + ((x * ~a[1]).sin * ~b[1]) }; + +p = Pbind( + \dev, Ptime().collect(f), + \midinote, Pkey(\dev) + 60 + [0, 4], + \amp, 0.05, + \dur, 0.15 +); + +v = VarGui([ + \a, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2, + \b, { [0, 10, \lin, 0.01, rrand(0.0, 10)] } ! 2], + stream: p +).gui +) + +// add a hook that re-plots control function after every slider change + +( +u = Plotter(bounds: Rect(200, 200, 700, 500)); + +// evaluation points + +x = (0, 0.1..20); + +// EventStreamPlayer is run in separate Environment, +// function values have to be polled from there, +// evaluate function initially and add it as mouseUp slider action + +g = { u.value_(f.inEnvir(v.envirs.first).(x)).refresh }; + +g.(); + +v.addSliderAction(g); +) + + + +////////////////////////// + +// GUI example with two LFOs + + +( +// parametric control function + +f = { |x| (x * ~a[0]).sin * ~b[0] + ((x * ~a[1]).sin * ~b[1]) }; + +p = Pbind( + \dev, Ptime().collect(f), + \midinote, Pkey(\dev) + Pfunc { ~add }, + \amp, 0.05, + \dur, 0.15 +); + +// add some harmonies + +q = Padd(\midinote, [-12, -7, 0, 5], p); +r = Padd(\midinote, [0, 2.5], p); + +v = VarGui([70, 55].collect { |x| [ + \a, { [0, 5, \lin, 0.01, rrand(0.0, 5)] } ! 2, + \b, { [0, 5, \lin, 0.01, rrand(0.0, 5)] } ! 2, + \add, [x-2, x+2, \lin, 0.01, x] + ] }, stream: [r,q], quant: 0.15 +).gui +) + +// add a hook that re-plots control function after every slider change + +( +u = Plotter(bounds: Rect(200, 200, 700, 500)); + +// evaluation points + +x = (0, 0.1..20); + +// EventStreamPlayer is run in separate Environment, +// function values have to be polled from there, +// evaluate function initially and add it as mouseUp slider action + +g = { u.value_(v.envirs.collect { |e| f.inEnvir(e).(x) }).refresh }; + + +g.(); + +v.addSliderAction(g); +) + +:: + + +anchor::Ex.1b:: +subsection::Ex.1b: Envelopes + +code:: + +( +e = Env([0, 10, 0], [2,1], \sin); +e.plot; +) + +// currently (SC 3.4.4) this will play the envelope once +// and then continue with the end value + +( +p = Pbind( + \dev, e, + \midinote, Pkey(\dev) + 60 + [0, 4], + \amp, 0.05, + \dur, 0.15 +).play; +) + +p.stop; + + +// you can use modulo calculus for looping + +( +p = Pbind( + \dev, Ptime().collect { |t| e[t % (e.times.sum)] }, + \midinote, Pkey(\dev) + 60 + [0, 4], + \amp, 0.05, + \dur, 0.15 +).play; +) + +p.stop; + + +////////////////////////// + +// example with GUI + +( +n = 5; + +p = Pbind( + \dev, Ptime().collect { |t| e[t % (e.times.sum)] }, + \midinote, Pkey(\dev) + 60 + [0, 4], + \amp, 0.05, + \dur, 0.15 +); + +v = VarGui([ + \levels, { [-15, 15, \lin, 0.01, rrand(-15.0, 15)] } ! n, + \times, { [0.5, 3, \lin, 0.01, rrand(0.5, 3)] } ! (n-1), + \curves, { [0, 7, \lin, 1, rrand(0, 7)] } ! (n-1), + \stretch, [0.1, 10, \lin, 0.01, 1]], + stream: p +).gui; +) + +// add a hook that plots envelope after every slider change + +( +u = Plotter(bounds: Rect(200, 200, 700, 500)); + +g = { + v.envirs.first.use { e = Env(~levels, ~times * ~stretch, ~curves) }; + u.value_(e.asSignal).refresh; +}; + +g.(); + +v.addSliderAction(g); +) + +:: + + + +anchor::Ex.1c:: +subsection::Ex.1c: SharedOut / shared memory + +SharedOut will be deprecated in future releases of SC and replaced by a shared memory mechanism (Tim Blechmann). +SharedOut is at least included in version 3.4.4. + +code:: + +// internal server needed for all examples with SharedOut, +// shared memory also works with local server + +( +s = Server.internal; +Server.default = s; +s.boot; +) + +// start LFO + +x = { SharedOut.kr(0, LFDNoise3.kr(0.3, 20, 70)) }.play; + + +// play event pattern + +( +p = Pbind( + \dur, 0.15, + \midinote, Pfunc { s.getSharedControl(0) } +).play; +) + +( +p.stop; +x.free; +) + +////////////////////////// + +// example with GUI + +// ATTENTION: this version of the example works with SC versions > 3.4.4 +// in which SharedOut is still supported and which already include +// the fix of a minor bug which blocked adding of SynthDefs. +// See below for an equivalent example with shared memory. + +// If you're using a version <= 3.4.4 you can fix it by yourself, +// adding this method to SharedOut and recompile: +// *numFixedArgs { ^1 } + +// ... or take the example version below the following version + +( +s = Server.internal; +Server.default = s; +s.boot; +) + +( +SynthDef(\control, { |midiCenter, dev, devFreq| SharedOut.kr(0, LFDNoise3.kr(devFreq, dev, midiCenter)) }).add; + +p = Pbind( + \dur, 0.15, + \midinote, Pfunc { s.getSharedControl(0) } + [0, 4] +); + +// start control synth before stream + +v = VarGui(synthCtr: [ + \midiCenter, [50, 80, \lin, 0.01, 70], + \dev, [0, 20, \lin, 0.01, 20], + \devFreq, [0, 3, \lin, 0.01, 0.5]], + synth: \control, stream: p +).gui(playerPriority: \synth); +) + + +// this version of the example works also with SC versions <= 3.4.4 + +( +SynthDef(\control, { |midiCenter, dev, devFreq| SharedOut.kr(0, LFDNoise3.kr(devFreq, dev, midiCenter)) }).send(s); +) + +( +x = Synth(\control).register; + +// or start paused: +// x = Synth.newPaused(\control).register; + +p = Pbind( + \dur, 0.15, + \midinote, Pfunc { s.getSharedControl(0) } + [0, 4] +); +) + +( +v = VarGui(synthCtr: [ + \midiCenter, [50, 80, \lin, 0.01, 70], + \dev, [0, 20, \lin, 0.01, 20], + \devFreq, [0, 3, \lin, 0.01, 0.5]], + synth: x, stream: p +).gui(playerPriority: \synth); +) + + +// shared memory example, SC version >= 3.5 +// start LFO + +c = Bus.control(s, 1); + +x = { Out.kr(c, LFDNoise3.kr(0.3, 20, 70)) }.play; + + +// play event pattern + +( +p = Pbind( + \dur, 0.15, + \midinote, Pfunc { c.getSynchronous } +).play; +) + +( +p.stop; +x.free; +) + +:: + + +anchor::Ex.1d:: +subsection::Ex.1d: HS / PHS and related + +With link::Classes/HS:: server values can be used in link::Classes/PHS:: objects which mimic event patterns. This is achieved by an OSC demand and respond mechanism which introduces a small amount of additional latency. It works with local and internal server, see link::Guides/Guide_to_HS_and_HSpar:: for further details. Using the HS family with VarGui is discussed in link::Tutorials/HS_with_VarGui::. + +The HS / PHS approach would especially be of interest if control behaviour could more easily be defined by server means than in SC lang (e.g. specific and / or nested UGens) but data should also be further manipulated in the language (e.g. for some kind of combinatorial use such as harmonic or polyphonic calculations). + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// a HS contains the control synth definition but will also hold playing Synth instances + +h = HS(s, { |midiCenter = 70, dev = 20, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }); + + +// a PHS refers to a HS and, when played, takes control over the control synth + +p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) + [0, 4] ]).play; + + +// stop player and control synth + +p.free; + +:: + + +Methods of linked playing / stopping and resuming (stream + help synth) are supported as well as reference to an already playing link::Classes/HS:: by link::Classes/PHSuse::. Various kinds of control synth control and synth value reference are possible with two or more help synths (see link::Classes/HSpar::, link::Classes/PHSpar:: and link::Classes/PHSparUse::). + + +anchor::Ex.1e:: +subsection::Ex.1e: audio synths reading from a control bus, discretized + +Derived from (2a), disadvantage: SynthDef must be adapted to control needs beforehand. + +code:: + +( +c = Bus.control(s,1); +d = Bus.control(s,1); + +SynthDef(\perc_1e, {|amp = 0.1, bus, att = 0.01, rel = 1| + var in = In.kr(bus, 1); + Out.ar(0, (SinOsc.ar(Latch.kr(in, in).midicps, 0, amp) * + EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2) +}).add; +) + +( +x = { Out.kr(c, LFDNoise3.kr(1, 5, 75)) }.play; +y = { Out.kr(d, LFDNoise3.kr(1, 5, 65)) }.play; + +p = Pbind( + \instrument, \perc_1e, + \dur, 0.3, + \amp, 0.07, + \bus, [c, d] +).play; +) + +( +p.stop; +x.free; +y.free; +) + +:: + + +anchor::Ex.1f:: +subsection::Ex.1f: Pseg + +Pseg can work like a kind of meta pattern for LFO-like control, patterns are used to pass envelope data. + +code:: + +( +p = Pbind( +    \note, Pseg(Pseq([0, Pwhite(3, 10, 1)], inf), Pseq([1, 3],inf), 'lin'), +    \dur, 0.2 +).play; +) + +p.stop; + +:: + + + +SECTION::2. Continuous LFO control + +anchor::Ex.2a:: +subsection::Ex.2a: audio synths reading from a control bus + +The disadvantage of this strategy (compared to 2b) is that synth definitions have to be written especially for control purposes. It must be known in advance which parameters should be controlled by another synth. + +code:: + +( +c = Bus.control(s,1); + +SynthDef(\perc_2a, {|amp = 0.1, bus = 0, att = 0.01, rel = 0.25| + Out.ar(0, (SinOsc.ar(In.kr(bus, 1).midicps, 0, amp) * + EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2) +}).add; +) + +( +x = { Out.kr(c, LFDNoise3.kr(3, 10, 65)) }.play; + +p = Pbind( + \instrument, \perc_2a, + \dur, 0.3, + \bus, c +).play; +) + +( +p.stop; +x.free; +) + +:: + + + +anchor::Ex.2b:: +subsection::Ex.2b: audio synths mapped to a control bus + +In general more practical than (2a), though by SC vs 3.4.4 reserved keys (e.g. \freq) can't be mapped to a bus, under these circumstances args would have to be renamed. + +code:: + +( +c = Bus.control(s,1); +d = Bus.control(s,1); + +SynthDef(\perc_2b, {|amp = 0.1, midi = 60, att = 0.01, rel = 0.25| + Out.ar(0, (SinOsc.ar(midi.midicps, 0, amp) * + EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2) +}).add; +) + +( +x = { Out.kr(c, LFDNoise3.kr(1, 5, 75)) }.play; +y = { Out.kr(d, LFDNoise3.kr(1, 5, 65)) }.play; + +p = Pbind( + \instrument, \perc_2b, + \dur, 0.3, + \midi, [c, d].collect(_.asMap) +).play; +) + +( +p.stop; +x.free; +y.free; +) + + +////////////////////////// + +// example with GUI + + +( +c = Bus.control(s,1); +d = Bus.control(s,1); + +SynthDef(\perc_2b, {|amp = 0.1, midi = 60, att = 0.01, rel = 0.25| + Out.ar(0, (SinOsc.ar(midi.midicps, 0, amp) * + EnvGen.ar(Env.perc(att, rel), doneAction: 2))!2) +}).add; + +SynthDef(\control_2b, { |midiCenter = 70, dev = 20, devFreq = 1, out = 0| + Out.kr(out, LFDNoise3.kr(devFreq, dev, midiCenter)) +}).add; +) + +( +p = Pbind( + \instrument, \perc_2b, + \dur, Pfunc { ~dur }, + // following values will be collections of two elements + \amp, Pfunc { ~amp }, + \att, Pfunc { ~att }, + \rel, Pfunc { ~rel }, + \midi, [c, d].collect(_.asMap) +); + +// in gui start control synths before stream player ! + +v = VarGui([ + \dur, [0.05, 0.5, \lin, 0.005, 0.2], + // setting envir variables to collections of two elements + \amp, [0, 0.1, \lin, 0.005, 0.07] ! 2, + \att, [0.005, 0.1, \lin, 0.005, 0.01] ! 2, + \rel, [0.005, 0.5, \lin, 0.005, 0.1] ! 2 + ], + 2.collect { |i| + var bus = [c,d][i].index; + [\midiCenter, [60, 80, \lin, 0.01, [65, 75][i] ], + \dev, [0, 10, \lin, 0.01, 10], + \devFreq, [0, 3, \lin, 0.01, 0.5], + \out, [bus, bus, \lin, 1, bus]] + }, p, \control_2b ! 2 +).gui(sliderPriority: \synth, playerPriority: \synth); +) + +:: + diff --git a/HelpSource/Tutorials/Event_patterns_and_array_args.schelp b/HelpSource/Tutorials/Event_patterns_and_array_args.schelp new file mode 100644 index 0000000..e6f47ac --- /dev/null +++ b/HelpSource/Tutorials/Event_patterns_and_array_args.schelp @@ -0,0 +1,678 @@ + + +TITLE::Event patterns and array args +summary::setting and passing arrays and envelopes via patterns +categories:: Libraries>miSCellaneous>General Tutorials, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous + + +DESCRIPTION:: + +This tutorial covers some use cases of array args, especially passing arrays to synths with patterns. + + +anchor::Ex.1:: +SECTION::Ex.1: Alternative writing of arrayed args in SynthDefs + + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// SynthDef with array of overtone weights, +// weights can additionally be influenced with a dampExp arg unequal to 0, +// see examples below. + +( +// The standard way to define array args: +// when appearing within the list of args, a literal Array must be used, +// shortcut (1..8) generates an Array with Integers from 1 to 8 + +SynthDef(\array_1a, { |out = 0, freq = 440, otAmps = #[1,1,1,1,1,1,1,1], dampExp = 0, + att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02| + var sig, env, freqs, amps; + freqs = (freq * (1..8)).clip(20, 20000).lag(freqLag); + amps = ((otAmps / ((1..8) ** dampExp)).normalizeSum * amp).lag(otLag); + sig = SinOsc.ar(freqs, 0, amps); + env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2); + Out.ar(out, Splay.ar(sig) * env) +}).add +) + +// Note that SynthDef \array_1a uses the array arg's size (8) at two further places (arrays (1..8)). +// As a literal Array, by its nature, requires the explicit writing of its items, +// this becomes arkward with larger arrays and/or rewriting the SynthDef with other sizes. +// For those reasons the use of NamedControl turns out to be very convenient with array args, +// it also gives an easy way of lagging. + + +( +// Alternative to SynthDef \array_1a using NamedControl: +// Although a NamedControl can be written at any position within the SynthDef, +// it's a useful convention to invent it directly after the args list +// by assigning it to a variable of the same name (so code with literal Array args can be reused easily). +// With NamedControl the array size can now also be written as a variable, +// which allows to define SynthDefs with different array sizes on the fly. +// Also note NamedControl's shortcuts aSymbol.kr / aSymbol.kr +// which make its use even more comfortable. + +// define size for SynthDef +n = 8; + +// define SynthDef +// shortcut 1!n (short for 1.dup(n)) generates an Array of size n filled with 1. + +SynthDef(\array_1b, { |out = 0, freq = 440, dampExp = 0, + att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02| + var otAmps = NamedControl.kr(\otAmps, 1!n); // shortcut: otAmps = \otAmps.kr(1!n); + var sig, env, freqs, amps; + freqs = (freq * (1..n)).clip(20, 20000).lag(freqLag); + amps = ((otAmps / ((1..n) ** dampExp)).normalizeSum * amp).lag(otLag); + sig = SinOsc.ar(freqs, 0, amps); + env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2); + Out.ar(out, Splay.ar(sig) * env) +}).add +) + + +// As array sizes of SynthDefs are fixed you might want to define for a number +// of Integers and name the SynthDefs appropriately. +// Here's such a "SynthDef factory": +// we get SynthDefs of names \array_1b_1, ..., \array_1b_16 with corresponding array sizes, +// see Ex.3b for a use case. + +( +(1..16).do { |n| + var name = \array_1b ++ \_ ++ n; + SynthDef(name, { |out = 0, freq = 440, dampExp = 0, + att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02| + var otAmps = NamedControl.kr(\otAmps, 1!n); // shortcut: otAmps = \otAmps.kr(1!n); + var sig, env, freqs, amps; + freqs = (freq * (1..n)).clip(20, 20000).lag(freqLag); + amps = ((otAmps / ((1..n) ** dampExp)).normalizeSum * amp).lag(otLag); + sig = SinOsc.ar(freqs, 0, amps); + env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2); + Out.ar(out, Splay.ar(sig) * env) + }).add +} +) + +:: + + +SECTION::2. Setting array args and array fields of a running synth + + +anchor::Ex.2a:: +subsection::Ex.2a: Setting array args of a running synth + +code:: + +// start Synth, SynthDefs \array_1a, \array_1b and \array_1b_8 are equivalent + +x = Synth(\array_1a, [freq: 300, amp: 0.2]) + + +// only odd partials (clarinet-like) + +x.set(\otAmps, [1, 0, 1, 0, 1, 0, 1, 0]) + + +// emphasize one partial + +x.set(\otAmps, [1, 0, 1, 0, 1, 5, 1, 0]) + + +// only lower ones + +x.set(\otAmps, [1, 1, 1, 1, 0, 0, 0, 0]) + + +// default again + +x.set(\otAmps, [1, 1, 1, 1, 1, 1, 1, 1]) + + + +// force lower partials with dampExp > 0 + +x.set(\dampExp, 1.5) + + +// force higher partials with dampExp < 0 + +x.set(\dampExp, -1.5) + + +// default again + +x.set(\dampExp, 0) + + +// release + +x.release + +:: + + + +anchor::Ex.2b:: +subsection::Ex.2b: Setting array args of a running synth with Pbind of event type \set + + +For many use cases Pmono (see link::#Ex.2c::) is the most practical solution as it doesn't require explicit starting of a synth. However sometimes it is necessary to access the running synth itself, then a Pbind with event type \set is a good choice. + + +code:: + + +// start Synth silently + +x = Synth(\array_1a, [freq: 200, amp: 0]) + + +// Pbind of event type set: +// args to be set must be listed. +// Note that the array arg requires double brackets (syntactic distinction from setting multiple nodes) + +( +p = Pbind( + \dur, 0.2, + \type, \set, + \id, x, + \args, #[freq, amp, dampExp, otAmps], // must be given explicitely + \midinote, Pwhite(45.0, 70), // for midinote freq must be set + \amp, 0.3, + \dampExp, Pwhite(0, 3), + \otAmps, [[2, 1, 3, 2, 1, 2, 2, 1]] // double brackets for array arg ! +).play +) + +( +// stop EventStreamPlayer and release Synth + +p.stop; +x.release; +) + + + +// start Synth silently + +x = Synth(\array_1a, [freq: 200, amp: 0]); + + +// Sequencing the array arg: +// rising spectral shape, falling fundamental + +( +// Array for Pseq, we need an array of doubly bracketed arrays or +// ref'd arrays as in Ex. 2c. + +o = [ + [[1, 1, 0, 0, 0, 0, 0, 0]], + [[1, 0, 1, 0, 0, 0, 0, 0]], + [[1, 1, 0, 1, 0, 0, 0, 0]], + [[1, 0, 1, 0, 1, 0, 0, 0]], + [[1, 1, 0, 1, 0, 1, 0, 0]], + [[1, 0, 1, 0, 1, 0, 1, 0]], + [[1, 0, 0, 1, 0, 1, 0, 1]] +]; + +p = Pbind( + \dur, 0.2, + \type, \set, + \id, x, + \args, #[freq, amp, otAmps], // must be given explicitely + \midinote, Pn(Plazy { Pseq((70..50)) / rrand(1, 1.2) }), + \amp, 0.3, + \otAmps, Pseq(o, 30) +).play +) + +( +// stop EventStreamPlayer and release Synth + +p.stop; +x.release; +) + + + + +:: + + +anchor::Ex.2c:: +subsection::Ex.2c: Setting array args of a running synth with Pmono + + +Rewriting second example of 2b, shorter with Pmono. Instead of doubly bracketed arrays you can choose Refs of Arrays also. Note that this alternative is not valid for a single nested Array as in the first example of link::#Ex.2b:: . + +code:: + +( +o = [ + `[1, 1, 0, 0, 0, 0, 0, 0], + `[1, 0, 1, 0, 0, 0, 0, 0], + `[1, 1, 0, 1, 0, 0, 0, 0], + `[1, 0, 1, 0, 1, 0, 0, 0], + `[1, 1, 0, 1, 0, 1, 0, 0], + `[1, 0, 1, 0, 1, 0, 1, 0], + `[1, 0, 0, 1, 0, 1, 0, 1] +]; + +p = Pmono(\array_1a, + \dur, 0.2, + \midinote, Pn(Plazy { Pseq((70..50)) / rrand(1, 1.2) }), + \amp, 0.3, + \otAmps, Pseq(o, 30) +).play +) + + +// stop EventStreamPlayer from Pmono (synth is released also) + +p.stop; + +:: + + +anchor::Ex.2d:: +subsection::Ex.2d: Setting i-th fields of a running synth + + +code:: + +// start Synth + +x = Synth(\array_1a, [freq: 200, amp: 0.3]) + + +// by default otAmps equals [1, 1, 1, 1, 1, 1, 1, 1] + +// Since SC 3.6.x there exists method seti for setting single elements of arrays: +// turn off high overtones + +x.seti(\otAmps, 7, 0) + +x.seti(\otAmps, 6, 0) + +x.seti(\otAmps, 5, 0) + + +x.release; + + +// With older SC versions you can use the following helper functions to achieve the same. +// This requires that the SynthDef has been added in order to have control arg info in SynthDescLib. + +( +~getCtlIndex = { |defName, argName, index| +    var x = SynthDescLib.global.at(defName.asSymbol).controls +        .collect({|x| x.name.asSymbol }).indexOf(argName.asSymbol); +    x !? { x + index }; +}; + +~setiID = { |server, defname, nodeID, key, index, value| +    server.sendMsg(15, nodeID, ~getCtlIndex.(defname, key, index), value); +}; + + +~seti = { |node, key, index, value| +    ~setiID.(node.server, node.defName, node.nodeID, key, index, value); +}; +) + + +// start Synth + +x = Synth(\array_1a, [freq: 200, amp: 0.5]) + + +// turn off high overtones + +~seti.(x, \otAmps, 7, 0) + +~seti.(x, \otAmps, 6, 0) + +~seti.(x, \otAmps, 5, 0) + +x.release; + + +:: + + + +anchor::Ex.2e:: +subsection::Ex.2e: Setting i-th fields of a running synth with patterns + + +For SC versions before invention of method seti use helper functions from link::#Ex.2d:: in Pbind. + +code:: + +// start Synth + +x = Synth(\array_1a, [freq: 200, amp: 0.3]) + + +// sequence setting of single fields +// As this is currently not integrated with Pmono or event type \set +// it must be done explicitely. Method 'makeBundle' with server latency arg +// ensures that array field setting is done in parallel to +// other settings triggered by the event. + +( +// continously subtract and add 7 overtones + +p = Pbind( + \type, \rest, + \dur, 0.2, + \otAmp, Pstutter(7, Pseq([0,1], inf)), + \amp, 0.3, + \i, Pn(Pshuf((1..7))), +// use Function ~seti (2d) for SC versions without method seti: + \do, Pfunc { |e| s.makeBundle(s.latency, { ~seti.(x, \otAmps, e.i, e.otAmp) }) } +// for newer SC versions with method seti you can use this line instead: +// \do, Pfunc { |e| s.makeBundle(s.latency, { x.seti(\otAmps, e.i, e.otAmp) }) } + ).trace.play +) + +// stop player and synth + +( +p.stop; +x.release; +) + + +// This approach can be extended by setting more than one field per event. +// In some cases this might be a reasonable alternative to setting whole arrays +// of running synths (2b, 2c), which requires more OSC traffic. + +// start Synth from Ex. 1 with 16 overtones + +x = Synth(\array_1b_16, [freq: 100, amp: 0.3]) + +( +// lists for bookkeeping of substracted and added overtones +a = (1..16).asList; +b = List[]; + +// Function to shovel indices from list to list + +f = { |list1, list2| + var x = list1.choose; + list1.remove(x); + list2.add(x); + x +}; + +// continously subtract and add 5 x 3 overtones + +p = Pbind( + \type, \rest, + \dur, 0.2, + \otAmp, Pstutter(5, Pseq([0,1], inf)), + \amp, 0.3, + // shoveling indices from a to b and back, outputting sorted index tripels + \i, Pseq([ + Pfinval(5, Pclump(3, Pfunc { f.(a, b) } )), + Pfinval(5, Pclump(3, Pfunc { f.(b, a) } )) + ], inf).collect(_.sort), +// use Function ~seti (2d) for SC versions without method seti: + \do, Pfunc { |e| s.makeBundle(s.latency, { e.i.do { |j| ~seti.(x, \otAmps, j, e.otAmp) } }) } +// for newer SC versions with method seti you can use this line instead: +// \do, Pfunc { |e| s.makeBundle(s.latency, { e.i.do { |j| x.seti(\otAmps, j, e.otAmp) } }) } +).trace.play +) + +// stop player and synth + +( +p.stop; +x.release; +) + +:: + + +anchor::Ex.2f:: +subsection::Ex.2f: Alternatives with demand ugens + + + +Besides from passing arrays, array sequencing can be done within synths by demand ugens. This is saving OSC bandwidth, especially with large arrays and short durations, for more complicated sequencing tasks coding might be harder than with patterns. + + +code:: + +( +// array sequencing within SynthDef + +q = [ + [1, 1, 0, 0, 0, 0, 0, 0], + [1, 0, 1, 0, 0, 0, 0, 0], + [1, 1, 0, 1, 0, 0, 0, 0], + [1, 0, 1, 0, 1, 0, 0, 0], + [1, 1, 0, 1, 0, 1, 0, 0], + [1, 0, 1, 0, 1, 0, 1, 0], + [1, 0, 0, 1, 0, 1, 0, 1] +]; + +// duration will have to be passed with a key unequal to reserved keyword \dur + +SynthDef(\array_1c, { |out = 0, freq = 440, dampExp = 0, duration = 0.2, + att = 0.01, rel = 0.6, amp = 0.1, gate = 1, freqLag = 0.02, otLag = 0.02| + var otAmps, sig, env, freqs, amps, arr; + otAmps = Demand.kr(Impulse.kr(1 / duration), 0, Dseq(q, inf)); + freqs = (freq * (1..8)).clip(20, 20000).lag(freqLag); + amps = ((otAmps / ((1..8) ** dampExp)).normalizeSum * amp).lag(otLag); + sig = SinOsc.ar(freqs, 0, amps); + env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2); + Out.ar(out, Splay.ar(sig) * env) +}).add; + +// SynthDef for complete server-side sequencing +// takes midiseq as array arg + +SynthDef(\array_1d, { |out = 0, dampExp = 0, duration = 0.2, divLo = 1, divHi = 1.2, + att = 0.01, rel = 0.6, amp = 0.3, gate = 1, freqLag = 0.02, otLag = 0.02| + var midiseq = \midiseq.kr((70..50)); + var trig, otAmps, sig, env, freq, freqs, amps, arr; + trig = Impulse.kr(1 / duration); + otAmps = Demand.kr(trig, 0, Dseq(q, inf)); + freq = Demand.kr(trig, 0, Dseq(midiseq, inf) / + Dstutter(midiseq.size, Dwhite(divLo, divHi))).midicps; + freqs = (freq * (1..8)).clip(20, 20000).lag(freqLag); + amps = ((otAmps / ((1..8) ** dampExp)).normalizeSum * amp).lag(otLag); + sig = SinOsc.ar(freqs, 0, amps); + env = EnvGen.ar(Env.asr(att, 1, rel), gate, doneAction: 2); + Out.ar(out, Splay.ar(sig) * env) +}).add +) + +( +// equivalent to Ex 2c +// still using a pattern for non-array sequencing + +p = Pmono(\array_1c, + \dur, 0.2, + \duration, Pkey(\dur), + \midinote, Pn(Plazy { Pseq((70..50)) / rrand(1, 1.2) }), + \amp, 0.3 +).play +) + +p.stop; + + +// equivalent, now all done by synth + +x = Synth(\array_1d) + + +// set midi sequence + +x.set(\midiseq, (50..70)) + +x.set(\midiseq, (70..50)) + +x.set(\midiseq, (70..50).scramble) + +x.release + + +:: + + +SECTION::3. Sequencing synths with array args by Pbind + + +anchor::Ex.3a:: +subsection::Ex.3a: Sequencing synths of same definition with array args by Pbind + + +code:: + +// Using a Pbind with array args is straightforward, +// it's just important to remember that arrays must be in +// double brackets (or wrapped into Refs). +// Written explicitely it looks a bit odd as you end up with +// three brackets at begin and end: +// Pseq([[[1, 1, 0, 0, 0, 0, 0, 0]], ... , [[1, 0, 0, 1, 0, 1, 0, 1]]], 100) + + +( +// Array o from definitions in Ex. 2b / 2c. + +o = [ + [[1, 1, 0, 0, 0, 0, 0, 0]], + [[1, 0, 1, 0, 0, 0, 0, 0]], + [[1, 1, 0, 1, 0, 0, 0, 0]], + [[1, 0, 1, 0, 1, 0, 0, 0]], + [[1, 1, 0, 1, 0, 1, 0, 0]], + [[1, 0, 1, 0, 1, 0, 1, 0]], + [[1, 0, 0, 1, 0, 1, 0, 1]] +]; + +// generating multiple nodes per event is also no problem, +// arrays from o are sent to both nodes here: + +p = Pbind( + \instrument, \array_1a, + \dur, 0.2, + \amp, 0.3, + \stepsPerOctave, 5, + \octave, 4, + \note, Pstutter(7, Pn(Pshuf((0..4)))) + [0, -4], + \otAmps, Pseq(o, 100) +).trace.play +) + +p.stop; + +:: + + +anchor::Ex.3b:: +subsection::Ex.3b: Sequencing synths with different array arg sizes by Pbind + + +By using the Array o in the last examples we did a kind of zeropadding: setting unused elements to zero. When altering one running synth (as with event type \set or Pmono) one can only save OSC messages if less than all fields are changed, see link::#Ex. 2e:: . When continuously generating new synths – as with 'normal' Pbind of type \note – there is another alternative: using SynthDefs of dedicated array arg sizes per event. This is the use case of a "SynthDef factory" as described in link::#Ex.1:: . + + + +code:: + + +( +// needs SynthDefs from "factory" in Ex. 1 + +q = [ + [[1, 1, 1]], + [[1, 1, 1, 1, 1]], + [[1, 0, 1, 0, 1, 0, 1, 0, 1]], + [[1, 1, 0, 1, 0, 1, 0, 1, 0, 1]] +]; + +p = Pbind( + \otAmps, Pn(Pshuf(q), 100), + \size, Pkey(\otAmps).collect { |x| x[0].size.asSymbol }, + \instrument, Pkey(\size).collect { |x| \array_1b_ ++ x }, // SynthDef depends on chosen otAmp array + \dur, 0.2, + \amp, 0.3, + \stepsPerOctave, 7, + \octave, 4, + \note, Pstutter(3, Pn(Pshuf((0..4)))) + Pn(Pshuf([[0, 2], [0, 4, 8], [0, -3, -5, -8]])) +).trace.play +) + +p.stop; + +:: + +anchor::Ex.4:: +SECTION::Ex.4 Sequencing synths with envelope array args by Pbind + +Env objects have a representation in a special Array format – which you can get with anEnv.asArray – the task of passing Env data to synths can thus be reduced to the task of passing Arrays in this special format. Nevertheless direct passing of Envs is possible also. + + +code:: + +( +// NamedControl is recommended in that case as a literal Array of special format would be impractical. +// Define a SynthDef with maximum envelope size you expect to pass + +SynthDef(\envArray_1, { |out = 0, freq = 440, amp = 0.1, timeScale = 1, gate = 1| + var sig, env, envArray, envSig; + envArray = Env([0, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0]).asArray; // works also without '.asArray' + env = \env.kr(envArray); // shortcut for NamedControl.kr(\env, envArray) + envSig = EnvGen.kr(env, gate, timeScale: timeScale, doneAction: 2); + sig = Saw.ar([freq, freq * 2.01], amp); + Out.ar(out, sig * envSig) +}).add +) + +// Pbind uses event type \on to avoid setting gate to 0 and receiving messages "node not found", +// synths are ended by envelopes anyway. + + +( +p = Pbind( + \type, Pshuf([\on, \on, \rest], inf), + \instrument, \envArray_1, + \dur, Pn(Pshuf([1, 1/2, 1/2]), 30), + \midinote, Pn(Pshuf((40..80))) + Pn(Pshuf([[0.5, 11.5], [0, 4], [0, -7], [-0.5, -9.5]])), + + // envData contains env types, determined by levels and times. + // Times are only relations, within the synthdef they are scaled by the timeScale arg. + \envData, Pn(Pshuf([ + [[0, 1, 0], [1, 1]], + [[0, 1, 1/4, 1, 0], [1, 1, 1, 1]], + [[0, 1, 1/4, 1, 1/4, 1, 0], [1, 1, 1, 1, 1, 1]] + ])), + + // *x splits the envData array into levels and times, Env is converted in to an Array automatically + \env, Pkey(\envData).collect { |x| Env(*x) }, + + // when wanting to pass the Array explicitely it would require + // wrapping into an additional Array which is necessary for passing: + // \env, Pkey(\envData).collect { |x| [Env(*x).asArray] }, + + \timeScale, Pfunc { |e| e.dur / e.envData[1].sum } +).trace.play; +) + +p.stop; + +:: + diff --git a/HelpSource/Tutorials/HS_with_VarGui.schelp b/HelpSource/Tutorials/HS_with_VarGui.schelp new file mode 100644 index 0000000..a222a1f --- /dev/null +++ b/HelpSource/Tutorials/HS_with_VarGui.schelp @@ -0,0 +1,360 @@ +TITLE::HS with VarGui +summary::using HS / HSpar with VarGui +categories:: Libraries>miSCellaneous>HS and HSpar, Libraries>miSCellaneous>GUI, Streams-Patterns-Events>HS and HSpar +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Guides/Guide_to_HS_and_HSpar, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Tutorials/Event_patterns_and_LFOs + +DESCRIPTION:: + +It is recommended to get familiar with the concepts of the link::Classes/HS:: / link::Classes/PHS:: and link::Classes/HSpar:: / link::Classes/PHSpar:: classes before combining them with VarGui, see link::Guides/Guide_to_HS_and_HSpar:: for an overview. + +Alternative control setups with event patterns and VarGui examples are discussed in link::Tutorials/Event_patterns_and_LFOs::. + +subsection::Differences to other control setups with event patterns and VarGui + +Instances of HS and PHS are hybrid objects in the sense that their functionality is not interchangeable with that of some (one might think at a first glance) related objects (Synths and Pbinds). A HS contains a SynthDef but will also hold Synths derived thereof. A PHS holds Pbind pairs but, when played, instantiates two EventStreamPlayers to be synchronized, also taking control over the used HS. A played PHSpar even controls a third player switching between running control synths. + +On the other hand VarGui is already prepared to accept synths / synth definitions and pbinds / eventstream players / tasks functions / tasks for generating synth and stream players. For plugging these concepts together it seems practical to use objects (resp. introduce adapting ones) that fit into what's already there. This can be achieved by two methods: + +numberedList:: + +## code::.newPaused::, applicable to PHS / PHSpar makes the used HS / HSpar generate a new paused Synth (or possibly several in case of PHSpar). Synths are returned by the method and can be passed to VarGui, which automatically detects their derivation from HS / HSpar and adapts gui functionality. + +## code::.asTask::, applicable to PHS / PHSpar and PHSuse / PHSparUse returns a wrapper Task for compound players of the PHS family. Playing and stopping the wrapper Task invokes playing and stopping behaviour of the underlying compound players, per default also taking control over playing and stopping the help synth(s). + +:: + +An alternative approach to link HS and HSpar with VarGui is shown in link::#Ex.3::. + + +anchor::Ex.1a:: +subsection::Ex.1a: HS / PHS + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +h = HS(s, { |midiCenter = 70, dev = 20, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }); + +p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) ]); + +// Instantiation and return of a new paused Synth from HS's synth definition + +x = p.newPaused; + +// second intermediate object: +// PHS's asTask method generates a wrapping task +// which will invoke expected player actions by notification + +// Note asTask's flag newEnvir, it determines if +// the player should run in a newly generated environment, defaults to true. +// This allows to take one PHS definition with varibles to be set in +// different environments (as with Pbind). + +t = p.asTask; + +// also compare play / stop behaviour with these options (default was hsStop: false, hsPlay: true): +// hsPlay = false will run Synth together with stream only for the first time + +// t = p.asTask(hsStop: true, hsPlay: true); +// t = p.asTask(hsStop: true, hsPlay: false); +// t = p.asTask(hsStop: false, hsPlay: false); +) + +( +// VarGui detects that a Synth derived from a HS has been passed: +// synth player stop / reset button and mode buttons are greyed out, +// pause button background color is blue as Synth is new and paused. +// Playing and stopping the stream player will also cause the synth's running +// (and stopping with asTask's option hsStop = true), +// however playing and stopping the help synth separately is still possible. + +// For Synths derived from HS / HSpar pushing the general stop button will +// only cause pausing - other synths will be freed - whereas Cmd. will free all synths, +// but ends HS gui control. Then a new VarGui would have to polled from reevaluated x and t. + +v = VarGui([], + [[\midiCenter, [50, 65, \lin, 0.01, 60], + \dev, [0, 10, \lin, 0.01, 10], + \devFreq, [0, 3, \lin, 0.01, 0.5] ]], + t, x +).gui; +) + +// free resources, PHSplayer is wrapped, so use Cmd-. or this + +h.free; + +:: + + +anchor::Ex.1b:: +subsection::Ex.1b: HS / PHS and PHSuse + +code:: + +( +h = HS(s, { |midiCenter = 70, dev = 20, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }); + +p = PHS(h, [], 0.15, [ \midinote, Pkey(\val) ]); +q = PHSuse(h, 0.3, [ \midinote, Pkey(\val) + 5 ]); +r = PHSuse(h, 0.4, [ \midinote, Pkey(\val) + 10 ]); + +x = p.newPaused; + +// quant arg for syncing + +t = [p,q,r].collect(_.asTask(quant: 0.3)); +) + +( +// The PHSplayer has control over the help synth, +// PHSusePlayers can't be played before, +// though it's possible to start all players together with shift-click. + +// For the same reason hsStop and hsPlay options are only available for the PHS-wrapping Task. + +// After PHSplayer has been started (and maybe paused) PHSusePlayers can be +// played and stopped separately. + + +v = VarGui([], + [[ \midiCenter, [50, 65, \lin, 0.01, 60], + \dev, [0, 10, \lin, 0.01, 10], + \devFreq, [0, 3, \lin, 0.01, 0.5] ]], + t, x +).gui; +) + +h.free; + +:: + + + +anchor::Ex.2a:: +subsection::Ex.2a: HSpar / PHSpar + +code:: + +( +h = HSpar(s, [ + { |midiCenter = 65, dev = 10, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }, + { |midiCenter = 90, dev = 10, devFreq = 1| LFSaw.kr(devFreq, 0, dev, midiCenter) } +]); + +// switching behaviour defined by hsIndices + +p = PHSpar(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [-4, 5] ]], + hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) +]); + +// for PHSpar this returns a collection of new paused help synths + +x = p.newPaused; + +t = p.asTask(quant: 0.3, hsStop: true); + +// You can specify start and stop options for selected Synths of HSpar +// with indices or collections of indices, e.g.: +// t = p.asTask(quant: 0.3, hsStop: 0); +) + +( +// Playing and stopping the PHSparPlayer's wrapper Task affects both help synths in parallel. + +v = VarGui([], + [[54.1, 3.85, 1.5], [60, 7.8, 2.7]].collect { |y| [ + \midiCenter, [50, 65, \lin, 0.01, y[0]], + \dev, [0, 10, \lin, 0.01, y[1]], + \devFreq, [0, 3, \lin, 0.01, y[2]]] + }, t, x +).gui; +) + +h.free; + +:: + + + +anchor::Ex.2b:: +subsection::Ex.2b: HSpar / PHSpar and PHSparUse + +code:: + +( +h = HSpar(s, [ + { |midiCenter = 65, dev = 10, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }, + { |midiCenter = 90, dev = 10, devFreq = 1| LFSaw.kr(devFreq, 0, dev, midiCenter) } +]); + +p = PHSpar(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [-4, 5] ]], + hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) +]); + +x = p.newPaused; + +q = PHSparUse(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [0, 9] ]], + hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) ] +); + +r = PHSparUse(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [2.5, 7] ]], + hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) ] +); + +t = [p,q,r].collect(_.asTask(quant: 0.3)); +) + +( +v = VarGui([], + [60, 75].collect { |y| [ + \midiCenter, [55, 85, \lin, 0.01, y], + \dev, [0, 10, \lin, 0.01, 10], + \devFreq, [0, 3, \lin, 0.01, 0.5]] + }, t, x +).gui; +) + +h.free; + +:: + + + +anchor::Ex.2c:: +subsection::Ex.2c: HSpar / PHSpar and PHSparUse with switch pattern + +code:: + +( +h = HSpar(s, [ + { |midiCenter = 65, dev = 10, devFreq = 1| LFDNoise3.kr(devFreq, dev, midiCenter) }, + { |midiCenter = 90, dev = 10, devFreq = 1| LFSaw.kr(devFreq, 0, dev, midiCenter) } +]); + + +// define event pattern to switch between the two help synths, +// switch times (average and random deviation) to be controlled from gui as well as +// chord structure determined by a single interval parameter + +p = PHSpar(h, + switchDur: Pfunc { ~swTmMid * (1 + rand2(~swTmDev)) }, + switchIndex: Pseq([0,1], inf), + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + Pfunc { [~int.neg, 0, ~int] } ]], + switchOn: true, // help synths to be resumed when active and ... + switchOff: true // ... to be paused when left - will be reflected by VarGui's button background colors +); + +x = p.newPaused; + +// chord structure of other pbinds will be taken from same variable ~int, so ... + +q = PHSparUse(h, [ 0.15, [ \midinote, Pkey(\val) + Pfunc { ~int.neg / 3 + [~int.neg, 0, ~int] } ]]); +r = PHSparUse(h, [ 0.15, [ \midinote, Pkey(\val) + Pfunc { ~int * 3 / 5 + [~int.neg, 0, ~int] } ]]); + +// ... players must be in the same environment, this is ensured by setting .asTask's flag newEnvir to false, +// all will be played and set in currentEnvironment. + +t = [p,q,r].collect(_.asTask(quant: 0.3, newEnvir: false)); +) + +( +v = VarGui([ + \swTmMid, [0.3, 1.5, \lin, 0.01, 1], + \swTmDev, [0, 0.5, \lin, 0.01, 0.5], + \int, [0, 12, \lin, 0.01, 8] + ], [60, 75].collect { |y| [ + \midiCenter, [55, 85, \lin, 0.01, y], + \dev, [0, 10, \lin, 0.01, 10], + \devFreq, [0, 3, \lin, 0.01, 0.5]] + }, t, x +).gui; +) + +// As can be seen in gui stopping with red stop button won't stop switching. +// Player had been started with asTask's default option switchStop = false +// and, as wrapped in a task, is not directly accessible. +// Anyway you can, as always, stop and free resources with Cmd-. or + +h.free; + +:: + + +anchor::Ex.3:: +subsection::Ex.3: Help Synths not passed explicitely + +This is an alternative approach if syncing control synths and streams is not important - whereas resetting control synths becomes an option. + +code:: + +( +// Actual help synths can be defined separately and fed into +// formal help synths via control busses + +// control synths hard-wired to allocated busses + +c = Bus.control(s, 2).index; + +SynthDef(\control_1, { |midiStart = 65, midiDiff = 15, duration = 10| + Out.kr(c, XLine.kr(midiStart, midiStart + midiDiff, duration) ) }).add; +SynthDef(\control_2, { |midiStart = 90, midiDiff = 15, duration = 10| + Out.kr(c+1, XLine.kr(midiStart, midiStart - midiDiff, duration) ) }).add; + +h = HSpar(s, [{ In.kr(c) }, { In.kr(c+1) }] ); + +// PHSpar and PHSparUse defined in same way as above but ... +// ... PHSparPlayer wrapper Task defaults to hsStop = false, +// so reading values from bus c is not stopped with pausing and +// PHSparUsePlayers can still get new values from "external" control synths + +p = PHSpar(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [-4, 5] ]], + hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) +]).asTask(quant: 0.3); + + +q = PHSparUse(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [0, 9] ]], + hsIndices: [ Pstutter(Prand([2, 3, 5, 11], inf), Pseq([0,1], inf)) ] +).asTask(quant: 0.3); + +r = PHSparUse(h, + pbindArgs: [ 0.15, [ \midinote, Pkey(\thisVal) + [2.5, 7] ]], + hsIndices: [ Pstutter(Prand([2,3,5, 11], inf), Pseq([0,1], inf)) ] +).asTask(quant: 0.3); +) + + +( +// Now control synths have to be started before streams ! +// Caps + shift click for parallel play action will work on cocoa, +// you can choose custom bundle latency (c) and set it slightly below server latency + +v = VarGui([], + [60, 80].collect { |x| [ + \midiStart, [50, 95, \lin, 0.01, x], + \midiDiff, [0, 30, \lin, 0.01, 15], + \duration, [1, 20, \lin, 0.01, 15]] + }, [p,q,r], [\control_1, \control_2] +).gui(playerPriority: \synth, sliderPriority: \synth); + +// modes of "external" control synths can be set +// resetting (starting new synths of same definition) is also possible +) + +// additional synths engaged here, so cleanup with Cmd-. or stopping in gui plus ... + +h.free; + +:: + diff --git a/HelpSource/Tutorials/Idev_suite.schelp b/HelpSource/Tutorials/Idev_suite.schelp new file mode 100644 index 0000000..441e3e4 --- /dev/null +++ b/HelpSource/Tutorials/Idev_suite.schelp @@ -0,0 +1,26 @@ +TITLE::Idev suite +summary::classes for number search with integer distance from a source, optionally avoiding repetitions within a span +categories:: Libraries>miSCellaneous>Idev suite, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/DIdev, Classes/PIdev, Classes/PLIdev + + +DESCRIPTION:: + +DIdev / PIdef / PLIdev search for numbers with integer distance from a source signal / pattern up to a given deviation. Repetitions within a lookback span are avoided, DIdev / PIdef / PLIdev randomly choose from possible solutions. Intended for search within integer grids (pitches, indices etc.), however applications with non-integer sources are possible, see examples. + +The main musical idea of these classes is, that it's often unwanted to have certain characteristics repeated within a perceptional time window. This might apply to melodic lines as well as to rhythmic patterns or sequences of timbre and can be continued in the domain of microsound. The principle can easily be understood with pitches, therefore most examples are of this kind. + +In the following example integers are searched within the neighbourhood of a rounded sine source. The hi and lo deviation is constant (+/-5) and a lookBack value of 3 garantuees that there are no repetitions of integer values within a group of 4 (e.g. find a closest repetition within the last 5 points). In general lookback and deviations can be dynamic, the source doesn't need to be rounded and the comparison threshold for the repetition check can also be passed as a dynamic argument. + + +image::attachments/Idev_suite/Idev_scheme_3.png:: + +note:: +It's the user's responsibility to pass a combination of deviation and lookback values that allows a possible choice, see examples. +:: + +note:: +In contrast to PIdev and PLIdev, DIdev needs to know maximum deviations (strong::minLoDev::, strong::maxHiDev::) beforehand. Together with strong::maxLookBack:: they determine multichannel sizes, which might be CPU-consuming. +:: + + diff --git a/HelpSource/Tutorials/Live_Granulation.schelp b/HelpSource/Tutorials/Live_Granulation.schelp new file mode 100755 index 0000000..ae7a700 --- /dev/null +++ b/HelpSource/Tutorials/Live_Granulation.schelp @@ -0,0 +1,900 @@ + + +TITLE::Live Granulation +summary::different approaches to live granulation with gui examples +categories:: Libraries>miSCellaneous>General Tutorials, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/Buffer_Granulation, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Tutorials/PLx_suite, Classes/PbindFx, Tutorials/kitchen_studies, Tutorials/Sieves_and_Psieve_patterns, Classes/PSPdiv, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + +DESCRIPTION:: + +This file is a complement to the link::Tutorials/Buffer_Granulation:: tutorial. It contains variants of granulation that are applied to an audio signal directly, without the explicit use of a buffer. As with buffer granulation there exist language-driven and server-driven as well as hybrid variants. Especially pattern-based live granulation raises certain accuracy issues, which are summarized in this tutorial. + +warning:: + +numberedList:: + +## Be careful with amplitudes! To reduce feedback I've built in tanh, LPF and delay into examples with SoundIn, though better use headphones to avoid feedback at all. For tips on reducing feedback or creative use of feedback see Nathaniel Virgo's Feedback quark. + +## Avoid too early freeing of audio buses: + +numberedList:: +## When there are still running synths, unintendedly sound might be routed to a processing resp. feedback chain. +## For the same reason don't free buses if they are hard-wired to SynthDefs, which you still want to use. +:: +You can free buses on occasion if you are sure that nothing is running and you won't need them again. Keep in mind that you can also (re-)start the server with a higher number of audio buses available (link::#Ex.2c::) + +## I haven't used below setups for live performances. Although all of them work stable for me as they are, in general hangs can occasionally happen with pattern-driven setups. Often this can be tracked down to sequences of extremely short event durations (and/or long grain durations). Where this can happen as a side-effect, thresholds can be built in. + +Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended - and if more complications are involved: testing without sound first, after saving your patch, might be a good idea. +:: +:: + +note:: +With the exception of link::#Ex.2d#(2d):: all examples use SoundIn, supposing to use input from your computer resp. soundcard. Depending on your setup you might have to change the standard input (bus = 0) passed to VarGui resp. the SoundIn ugen. Use headphones to avoid feedback! +:: + +note:: +All live granulation variants of this file can of course be applied to any signal, thus also to any playback of a buffer. Vice versa all variants from link::Tutorials/Buffer_Granulation:: can be applied to a buffer, which is occasionally (or continuously) filled with live input. +:: + + +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) +:: + +anchor::1:: +SECTION::1. Live granulation scheduled by server +subsection::Ex. 1a: Basic live granulation with GrainIn + +code:: +( +~audioBus_ex_1a = Bus.audio(s, 1); + +// pass envelopes with buffer, hanning is GrainIn's default anyway +h = Signal.hanningWindow(1000); +e = Buffer.loadCollection(s, h); + +SynthDef(\soundIn, { |out, in, ampIn = 1| + Out.ar(out, SoundIn.ar(in) * ampIn) +}).add; + +SynthDef(\live_gran_1a, { |out, in, envBuf, trigRate = 50, overlap = 0.5, panMax = 0.5, + panType = 0, amp = 1, minGrainDur = 0.001| + var inSig, sig, trig, grainDur, pan; + + inSig = In.ar(in, 1); + // reduce feedback + inSig = DelayC.ar(LPF.ar(inSig.tanh, 2000), 0.1, 0.01); + + trig = Impulse.ar(trigRate); + grainDur = max(trigRate.reciprocal * overlap, minGrainDur); + + // select L/R or random sequencing + pan = Demand.ar( + trig, + 0, + Dswitch1([ + Dseq([1, -1], inf), + Dwhite(-1, 1) + ], panType) + ) * min(panMax, 0.999); + + sig = GrainIn.ar( + 2, + trig, + grainDur, + inSig, + pan, + envBuf + ); + Out.ar(out, sig * EnvGate.new * amp); +}).add; +) + + +// to avoid feedback use with headphones + +( +// start granulation (first row) before to ensure right order +VarGui( + synthCtr: [ + [ + \envBuf, e.bufnum, + \in, ~audioBus_ex_1a.index, + \trigRate, [5, 500, \lin, 0, 50], + \overlap, [0.05, 3, \lin, 0, 0.5], + \panType, [0, 1, \lin, 1, 0], + \panMax, [0, 1, \lin, 0, 0.5], + \amp, [0, 1, \lin, 0, 0.1] + ],[ + \out, ~audioBus_ex_1a.index, + // you might have to pass a different 'in' bus for SoundIn + // depending on your setup + \in, 0, + \ampIn, [0, 1, \lin, 0, 1] + ] + ], + synth: [\live_gran_1a, \soundIn] +).gui +) + + +:: + +Even with overlapping grains, sequenced effect processing per grain is possible with GrainIn, but requires more effort, see link::Tutorials/Buffer_Granulation#Ex.1e in the Buffer Granulation tutorial::. + + +anchor::Ex.1b:: +subsection::Ex. 1b: Live granulation with server-driven enveloping + +In this example only non-overlapping grains are regarded, for overlapping, as with GrainIn, a multichannel approach as in link::Tutorials/Buffer_Granulation#Ex.1e#Ex.1e in the Buffer Granulation tutorial:: can be applied. In comparison to link::#1#live granulation example 1a:: there is hardly an advantage in this basic variant. However intermediate processings can be built into this SynthDef, which aren't possible in the above example, where granulation is encapsulated in a ugen, manipulation of the envelope signal could be one. + +code:: +( +~audioBus_ex_1b = Bus.audio(s, 1); + +// pass envelopes with buffer +h = Signal.hanningWindow(1000); +e = Buffer.loadCollection(s, h); + +SynthDef(\soundIn, { |out, in, ampIn = 1| + Out.ar(out, SoundIn.ar(in) * ampIn) +}).add; + +// suppose overlap < 1 + +SynthDef(\live_gran_1b, { |out, in, envBuf, trigRate = 50, overlap = 0.5, panMax = 0.5, + panType = 0, amp = 1, minGrainDur = 0.001, interpolation = 4| + var inSig, env, numFrames = BufFrames.kr(envBuf), startTrig, grainDur, + latchedTrigRate, latchedStartTrig, latchedOverlap, pan; + + inSig = In.ar(in, 1); + // reduce feedback + inSig = DelayC.ar(LPF.ar(inSig.tanh, 2000), 0.1, 0.01); + + startTrig = Impulse.ar(trigRate); + // why this ? - shape of envelope shouldn't be changed while application + latchedTrigRate = Latch.ar(K2A.ar(trigRate), startTrig); + latchedStartTrig = Impulse.ar(latchedTrigRate); + latchedOverlap = Latch.ar(K2A.ar(overlap), startTrig); + + latchedOverlap = max(latchedOverlap, latchedTrigRate * minGrainDur); + grainDur = (latchedOverlap / latchedTrigRate); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + latchedStartTrig, + latchedOverlap.reciprocal * latchedTrigRate * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + + pan = Demand.ar( + latchedStartTrig, + 0, + Dswitch1([ + Dseq([1, -1], inf), + Dwhite(-1, 1) + ], panType) + ) * panMax * 0.999; + + Out.ar(out, Pan2.ar(inSig * env * amp, pan) * EnvGate.new); +}).add +) + + +// to avoid feedback use with headphones + +( +// start granulation (first row) before to ensure right order +VarGui( + synthCtr: [ + [ + \envBuf, e.bufnum, + \in, ~audioBus_ex_1b.index, + \trigRate, [5, 500, \lin, 0, 50], + \overlap, [0.05, 0.99, \lin, 0, 0.5], + \panType, [0, 1, \lin, 1, 0], + \panMax, [0, 1, \lin, 0, 0.5], + \amp, [0, 1, \lin, 0, 0.1] + ],[ + \out, ~audioBus_ex_1b.index, + // you might have to pass a different 'in' bus for SoundIn + // depending on your setup + \in, 0, + \ampIn, [0, 1, \lin, 0, 1] + ] + ], + synth: [\live_gran_1b, \soundIn] +).gui +) + + +:: + + +anchor::2:: +SECTION::2. Live granulation driven by language + +The crucial point of this strategy is a kind of incompatibility of In.ar and OffsetOut. Normally we use OffsetOut for exact buffer granulation with patterns, as the start of the synth (the grain) is corrected by a shift (standard Out.ar is only able to start at control block boundaries). However, when In.ar and OffsetOut.ar are used in the same synth the read input signal is also shifted, which results in a correct grain distance but an fluctuating input delay. This can be overcome by a little trick: we can use OffsetOut to send a trigger to a bus, which indicates its correct delay. Then the trigger can be read in the same synth and trigger again a gated envelope for the input signal, the resulting grain can be output with normal Out.ar. So grain distances are correct and input is not fluctuating (see link::#Ex.2d:: for an accuracy comparison). Nevertheless language-driven sequencing is not sample-exact in realtime, no matter if In.ar is used or not, this is related to hardware control and cannot be overcome. This might be an issue with a strictly periodic input signal and very short grain distances. You can e.g. check out with granulation of a fixed-pitch triangular wave or similar, every few seconds or so there will happen an audible jump due to an irregular time interval, which is necessary for clock calibration; at that point there will, in general, also be a phase shift of the input signal (see last example of link::#Ex.2d::). This might not be noticed with an input of spoken voice e.g. Control block length is also a boundary for gated envelopes defined with EnvGen – here envelopes are established with an env buffer used by BufRd and Sweep ugens, a flexible method as Envelopes shape can be defined arbitrarily in language. + + +anchor::Ex.2a:: +subsection::Ex. 2a: Basic Pbind live granulation + +At that point I haven't seen a solution to pass the trigger bus as argument, in the example it is hard-wired. As the SynthDef uses a SetResetFF ugen, which relies on two triggers within control block length, grainDelta shouldn't be shorter than that. If shorter grainDeltas are required this would be possible with alternating SynthDefs and buses. For the same reason this SynthDef should only be used once at the same time by a Pbind/EventStreamPlayer. Alternatively – as in link::#Ex.2b:: – a SynthDef factory can produce a number of structurally equal SynthDefs bound to a number of buses. + + +code:: +( +// input bus and trigger bus +// trigger bus must be hard-wired in SynthDef though + +~audioBus_ex_2a = Bus.audio(s, 1); +~trigBus_ex_2a = Bus.audio(s, 1); + +// pass envelopes with buffer +h = Signal.hanningWindow(1000); +e = Buffer.loadCollection(s, h); + +SynthDef(\soundIn, { |out, in, ampIn = 1| + Out.ar(out, SoundIn.ar(in) * ampIn) +}).add; + +SynthDef(\live_gran_2a, { |out, inBus, envBuf, grainDelta, pan = 0, + overlap = 1, amp = 1, minGrainDur = 0.001, interpolation = 4| + + var inSig, offset, env, numFrames = BufFrames.ir(envBuf), gate, + defaultOffset = ControlRate.ir.reciprocal; + inSig = In.ar(inBus, 1); + + // reduce feedback + inSig = LPF.ar(inSig.tanh, 2000); + + // low overlap bound given by minimal grain duration + overlap = max(overlap, minGrainDur / grainDelta); + + // impulse for offset check + OffsetOut.ar(~trigBus_ex_2a, Impulse.ar(0)); + + // additional gate to start with 0 in delayed case + // this is necessary as OffsetOut outputs impulse twice + gate = SetResetFF.ar(In.ar(~trigBus_ex_2a)); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + In.ar(~trigBus_ex_2a), + (overlap * grainDelta).reciprocal * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + // to finish synth + Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2); + + // shifted accurate output + Out.ar(out, Pan2.ar(env * gate * inSig * amp, pan)); +}).add +) + + +// to avoid feedback use with headphones + +// start synth and event stream player + +( +p = Pbind( + \instrument, \live_gran_2a, + \inBus, ~audioBus_ex_2a, + \envBuf, e, + \dur, Pfunc { ~trigRate.reciprocal }, + \grainDelta, Pkey(\dur), + \overlap, Pfunc { ~overlap }, + \amp, Pfunc { ~amp }, + \pan, Pfunc { ~panMax } * PLseq([1, -1]), + \addAction, \addToTail +); + +VarGui([ + \trigRate, [20, 500, \lin, 0, 100], + \overlap, [0.1, 2, \lin, 0, 0.5], + \panMax, [0, 1, \lin, 0, 0.5], + \amp, [0, 1, \lin, 0, 0.1] + ],[ + \out, ~audioBus_ex_2a.index, + // you might have to pass a different 'in' bus for SoundIn + // depending on your setup + \in, 0, + \ampIn, [0, 1, \lin, 0, 1] + ], p, \soundIn +).gui +) + + +:: + + +anchor::Ex.2b:: +subsection::Ex. 2b: Parallel Pbind live granulation + +As trigger buses have to be hard-wired, a SynthDef factory produces a number of structurally equal SynthDefs bound to a number of buses. In this variant the granulation is combined with a bandpass filter. + +code:: +( +// input bus and trigger bus +// trigger bus must be hard-wired in SynthDef though + +~audioBus_ex_2b = Bus.audio(s, 1); + +// pass envelopes with buffer +h = Signal.hanningWindow(1000); +e = Buffer.loadCollection(s, h); + +SynthDef(\soundIn, { |out, in, ampIn = 1| + Out.ar(out, SoundIn.ar(in) * ampIn) +}).add; + +// "SynthDef factory", as each SynthDef neads hard-wired bus, make 3 of each + +~trigBus_ex_2b = { Bus.audio(s, 1) } ! 3; + +{ |i| + var name = \live_gran_2b ++ "_" ++ i.asString; + SynthDef(name, { |out, inBus, envBuf, grainDelta, pan = 0, rq = 0.1, center = 500, + overlap = 1, amp = 1, minGrainDur = 0.001, interpolation = 4| + + var sig, inSig, offset, env, numFrames = BufFrames.ir(envBuf), gate, + defaultOffset = ControlRate.ir.reciprocal; + inSig = In.ar(inBus, 1); + + // reduce feedback + inSig = LPF.ar(inSig.tanh, 2000); + + // amplitude compensation for lower rq of bandpass filter + inSig = BPF.ar(inSig, center, rq, (rq ** -1) * (400 / center ** 0.5)); + + // low overlap bound given by minimal grain duration + overlap = max(overlap, minGrainDur / grainDelta); + + // impulse for offset check + OffsetOut.ar(~trigBus_ex_2b[i], Impulse.ar(0)); + + // additional gate to start with 0 in delayed case + // this is necessary as OffsetOut outputs impulse twice + gate = SetResetFF.ar(In.ar(~trigBus_ex_2b[i])); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + In.ar(~trigBus_ex_2b[i]), + (overlap * grainDelta).reciprocal * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + // to finish synth + Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2); + + sig = env * gate * inSig * amp; + + // shifted accurate output + Out.ar(out, Pan2.ar(sig, pan)); + }).add +} ! 3 +) + + +// to avoid feedback use with headphones + +// start synth and event stream players + +( +// pattern maker, we need the three different instruments +p = { |i| Pbind( + \instrument, \live_gran_2b ++ "_" ++ i.asString, + \inBus, ~audioBus_ex_2b, + \envBuf, e, + \dur, Pfunc { ~trigRate.reciprocal }, + \grainDelta, Pkey(\dur), + \overlap, Pfunc { ~overlap }, + \rq, Pfunc { ~rq }, + \center, Pfunc { ~center }, + \amp, Pfunc { ~amp }, + \pan, Pfunc { ~panMax } * PLseq([1, -1]), + \addAction, \addToTail +) }; + +VarGui([ + \trigRate, [20, 500, \lin, 0, 100], + \overlap, [0.1, 2, \lin, 0, 0.5], + \panMax, [0, 1, \lin, 0, 0.5], + \center, [100, 3000, \exp, 0, 800], + \rq, [0.1, 1, \lin, 0, 0.1], + \amp, [0, 1, \lin, 0, 0.1] + ] ! 3,[ + \out, ~audioBus_ex_2b.index, + // you might have to pass a different 'in' bus for SoundIn + // depending on your setup + \in, 0, + \ampIn, [0, 1, \lin, 0, 1] + ], p ! 3, \soundIn +).gui +) + + +:: + + + +anchor::Ex.2c:: +subsection::Ex. 2c: Live granulation with PbindFx + +code:: +// extended ressources needed + +( +s.options.numPrivateAudioBusChannels = 1024; +s.options.memSize = 8192 * 16; +s.reboot; +) + + +( +// input bus and trigger bus +// trigger bus must be hard-wired in SynthDef though + +~audioBus_ex_2c = Bus.audio(s, 1); +~trigBus_ex_2c = Bus.audio(s, 1); + +// pass envelopes with buffer +h = Signal.hanningWindow(1000); +e = Buffer.loadCollection(s, h); + +SynthDef(\soundIn, { |out, in, ampIn = 1| + Out.ar(out, SoundIn.ar(in) * ampIn) +}).add; + + +// two fx SynthDefs + +SynthDef(\resample, { |out = 0, in, mix = 0.5, amp = 1, resampleRate = 44100| + var sig, inSig = In.ar(in, 2); + sig = Latch.ar(inSig, Impulse.ar(resampleRate)); + Out.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp); +}).add; + +SynthDef(\bpf, { |out = 0, in, freq = 440, rq = 0.1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = BPF.ar(inSig, freq, rq, (rq ** -1) * (400 / freq ** 0.5)); + Out.ar(out, (mix * sig + ((1 - mix) * inSig)) * amp); +}).add; + + +SynthDef(\live_gran_2c, { |out, inBus, envBuf, grainDelta, pan = 0, + overlap = 1, amp = 1, minGrainDur = 0.001, interpolation = 4| + + var inSig, offset, env, numFrames = BufFrames.ir(envBuf), gate, + defaultOffset = ControlRate.ir.reciprocal; + inSig = In.ar(inBus, 1); + + // reduce feedback + inSig = LPF.ar(inSig.tanh, 2000); + + // low overlap bound given by minimal grain duration + overlap = max(overlap, minGrainDur / grainDelta); + + // impulse for offset check + OffsetOut.ar(~trigBus_ex_2c, Impulse.ar(0)); + + // additional gate to start with 0 in delayed case + // this is necessary as OffsetOut outputs impulse twice + gate = SetResetFF.ar(In.ar(~trigBus_ex_2c)); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + In.ar(~trigBus_ex_2c), + (overlap * grainDelta).reciprocal * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + // to finish synth + Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2); + + // shifted accurate output + Out.ar(out, Pan2.ar(env * gate * inSig * amp, pan)); +}).add +) + + +( +// start without fx + +~fxOrder = 0; + +// playing the PbindFx in a new group ensures that soundIn synth is placed before when started later + +g = Group.new; + +p = PbindFx([ + \instrument, \live_gran_2c, + \inBus, ~audioBus_ex_2c, + // allow hard-wired bus (bus connections check) + \otherBusArgs, [\inBus, ~trigBus_ex_2c.index.asFloat], + \envBuf, e, + \dur, 1 / PL(\trigRate), + \grainDelta, Pkey(\dur), + \overlap, PL(\overlap), + \amp, PL(\amp), + \pan, PL(\panMax) * PLseq([1, -1]), + \fxOrder, PL(\fxOrder, envir: 't'), + \cleanupDelay, 0.1, + + \group, g + ],[ + \fx, \resample, + \mix, 1, + \amp, PL(\amp_resample), + \resampleRate, PL(\resampleRate_resample), + \cleanupDelay, 0.01 + ],[ + \fx, \bpf, + \freq, PL(\freq_bpf), + \rq, PL(\rq_bpf), + \mix, 1, + \amp, PL(\amp_bpf), + \cleanupDelay, 0.01 + ] +); + +VarGui([ + \trigRate, [20, 500, \lin, 0, 100], + \overlap, [0.1, 2, \lin, 0, 0.5], + \panMax, [0, 1, \lin, 0, 0.5], + \amp, [0, 1, \lin, 0, 0.1], + + \resampleRate_resample, [200, 3000, \exp, 0, 500], + \amp_resample, [0, 1, \lin, 0, 1], + + \freq_bpf, [50, 3000, \exp, 0, 200], + \rq_bpf, [0.1, 1, \lin, 0, 0.3], + \amp_bpf, [0, 1, \lin, 0, 1] + ],[ + \out, ~audioBus_ex_2c.index, + // you might have to pass a different 'in' bus for SoundIn + // depending on your setup + \in, 0, + \ampIn, [0, 1, \lin, 0, 1] + ], p, \soundIn +).gui( + varColorGroups: (0..8).clumps([4, 2, 3]), + tryColumnNum: 1, + labelWidth: 140, + sliderWidth: 350 +) +) + + +// check fxs and their params, mix is fixed to 1 + +// resample + +~fxOrder = 1 + + +// band pass + +~fxOrder = 2 + + +// resample -> band pass + +~fxOrder = [1, 2] + + +// band pass -> resample + +~fxOrder = [2, 1] + + +// fx alternations +// Pstutter with repeats equal 2 ensures L/R balance + +~fxOrder = Pstutter(2, PLseq([1, 2])) + +~fxOrder = Pstutter(2, PLseq([[1, 2], 1])) + +~fxOrder = Pstutter(2, PLseq([[1, 2], 2])) + + +~fxOrder = Pstutter(2, PLseq([[2, 1], 1])) + +~fxOrder = Pstutter(2, PLseq([[2, 1], 2])) + + +~fxOrder = Pstutter(2, PLseq([[1, 2], [2, 1]])) + + + +:: + + +anchor::Ex.2d:: +subsection::Ex. 2d: Accuracy comparison + +This example compares the inaccuracies occuring with "normal" usage of Out.ar and the usage of In.ar + OffsetOut.ar with the strategy recommended in link::#Ex.2a::. Run the three examples, the audio output is played and recorded into three files in the recordings directory (you get the path with thisProcess.platform.recordingsDir). + +code:: +// test with source of added sines, inaccuracies with straight use of Out.ar + +( +~audioBus_ex_2d1 = Bus.audio(s, 1); + +// pass envelopes with buffer +// envelope with sharp attack to make effect more clear +h = Env([0, 1, 1, 0], [1, 10, 1].normalizeSum, curve: \sine).discretize(1000); +e = Buffer.loadCollection(s, h); + +// sine as test signal +SynthDef(\sineIn, { |directOut, granOut, freq = 200, amp = 0.03, in| + freq = freq * (1..8); + Out.ar(directOut, SinOsc.ar(freq).sum * amp * EnvGate.new); + Out.ar(granOut, SinOsc.ar(freq).sum * amp); +}).add; + +// envelopes in left channel, granulation in right +SynthDef(\live_gran_shaky_1, { |out, inBus, envBuf, grainDelta, + overlap = 1, amp = 1, interpolation = 4| + + var inSig, offset, env, numFrames = BufFrames.ir(envBuf), + defaultOffset = ControlRate.ir.reciprocal; + inSig = In.ar(inBus, 1); + + // reduce feedback with sound in source + inSig = LPF.ar(inSig.tanh, 2000); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + 1, + (overlap * grainDelta).reciprocal * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + // to finish synth + Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2); + + Out.ar(out + 1, inSig * env); +}).add; + + +p = Pfindur(1, Pbind( + \instrument, \live_gran_shaky_1, + \inBus, ~audioBus_ex_2d1, + \envBuf, e, + \dur, 0.005, + \grainDelta, Pkey(\dur), + \overlap, 0.5, + \amp, 0.1, + \addAction, \addToTail +)); +) + + +( +// record live input and granulation (which comes with delay due to normal pbind latency) +// see the file in an editor then: +// distances are irregular due to Out ugen's accuracy limit control block boundary, +// though source signal is not delayed + +{ + ~date = Date.getDate.stamp; + ~fileName = thisProcess.platform.recordingsDir +/+ + ("live_gran_shaky_1" ++ "_" ++ ~date ++ ".aiff"); + s.record(~fileName); + s.sync; + + x = Synth(\sineIn, args: [directOut: 0, granOut: ~audioBus_ex_2d1]); + p.play; + + 1.5.wait; + x.release; + s.stopRecording; +}.fork +) + + + +///////////////////////// + +// test with source of added sines, inaccuracies with use of In.ar + OffsetOut.ar + +( +~audioBus_ex_2d2 = Bus.audio(s, 1); + +// pass envelopes with buffer +// envelope with sharp attack to make effect more clear +h = Env([0, 1, 1, 0], [1, 10, 1].normalizeSum, curve: \sine).discretize(1000); +e = Buffer.loadCollection(s, h); + +// sine as test signal +SynthDef(\sineIn, { |directOut, granOut, freq = 200, amp = 0.03, in| + freq = freq * (1..8); + Out.ar(directOut, SinOsc.ar(freq).sum * amp * EnvGate.new); + Out.ar(granOut, SinOsc.ar(freq).sum * amp); +}).add; + +// envelopes in left channel, granulation in right +SynthDef(\live_gran_shaky_2, { |out, inBus, envBuf, grainDelta, + overlap = 1, amp = 1, interpolation = 4| + + var inSig, offset, env, numFrames = BufFrames.ir(envBuf), + defaultOffset = ControlRate.ir.reciprocal; + inSig = In.ar(inBus, 1); + + // reduce feedback with sound in source + inSig = LPF.ar(inSig.tanh, 2000); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + 1, + (overlap * grainDelta).reciprocal * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + // to finish synth + Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2); + + OffsetOut.ar(out + 1, inSig * env); +}).add; + + +p = Pfindur(1, Pbind( + \instrument, \live_gran_shaky_2, + \inBus, ~audioBus_ex_2d2, + \envBuf, e, + \dur, 0.005, + \grainDelta, Pkey(\dur), + \overlap, 0.5, + \amp, 0.1, + \addAction, \addToTail +)); +) + + +// record live input and granulation (which comes with delay due to normal pbind latency) +// see the file in an editor then: +// distances are regular due to OffsetOut, but source signal is delayed +// between 0 and control block length + +( +{ + ~date = Date.getDate.stamp; + ~fileName = thisProcess.platform.recordingsDir +/+ + ("live_gran_shaky_2" ++ "_" ++ ~date ++ ".aiff"); + s.record(~fileName); + s.sync; + + x = Synth(\sineIn, args: [directOut: 0, granOut: ~audioBus_ex_2d2]); + p.play; + + 1.5.wait; + x.release; + s.stopRecording; +}.fork +) + + + +///////////////////////// + +// test with source of added sines, granulation done as in Ex.2a + +( +// input bus and trigger bus +// trigger bus must be hard-wired in SynthDef though + +~audioBus_ex_2d3 = Bus.audio(s, 1); +~trigBus_ex_2d3 = Bus.audio(s, 1); + + +// pass envelopes with buffer +// envelope with sharp attack to make effect more clear +h = Env([0, 1, 1, 0], [1, 10, 1].normalizeSum, curve: \sine).discretize(1000); +e = Buffer.loadCollection(s, h); + +// sine as test signal +SynthDef(\sineIn, { |directOut, granOut, freq = 200, amp = 0.03, in| + freq = freq * (1..8); + Out.ar(directOut, SinOsc.ar(freq).sum * amp * EnvGate.new); + Out.ar(granOut, SinOsc.ar(freq).sum * amp); +}).add; + +// envelopes in left channel, granulation in right +SynthDef(\live_gran_ok, { |out, inBus, envBuf, grainDelta, gate, + overlap = 1, amp = 1, interpolation = 4| + + var inSig, offset, env, numFrames = BufFrames.ir(envBuf), + defaultOffset = ControlRate.ir.reciprocal; + inSig = In.ar(inBus, 1); + + // reduce feedback with sound in source + inSig = LPF.ar(inSig.tanh, 2000); + + // impulse for offset check + OffsetOut.ar(~trigBus_ex_2d3, Impulse.ar(0)); + + // necessary additional gate to start with 0 in delayed case + gate = SetResetFF.ar(In.ar(~trigBus_ex_2d3)); + + env = BufRd.ar( + 1, + envBuf, + Sweep.ar( + In.ar(~trigBus_ex_2d3), + (overlap * grainDelta).reciprocal * numFrames, + ).clip(0, numFrames - 1), + interpolation: interpolation + ); + // to finish synth + Line.ar(dur: overlap * grainDelta + defaultOffset, doneAction: 2); + + // shifted accurate output + Out.ar(out + 1, inSig * env * gate); +}).add; + + +p = Pfindur(1, Pbind( + \instrument, \live_gran_ok, + \inBus, ~audioBus_ex_2d3, + \envBuf, e, + \dur, 0.005, + \grainDelta, Pkey(\dur), + \overlap, 0.5, + \amp, 0.1, + \addAction, \addToTail +)); +) + + +( +// record live input and granulation (which comes with delay due to normal pbind latency) +// see the file in an editor then: +// distances are regular due to OffsetOut, and source signal is not delayed + +// However also in this case, because of hardware output calibration, it happens that phase shifts +// occur in granulation. +// This is currently unavoidable in SC's realtime mode, but probably irrelevant in most cases of +// live granulation, where there is no strictly periodic input signal + +{ + ~date = Date.getDate.stamp; + ~fileName = thisProcess.platform.recordingsDir +/+ + ("\live_gran_ok" ++ "_" ++ ~date ++ ".aiff"); + s.record(~fileName); + s.sync; + + x = Synth(\sineIn, args: [directOut: 0, granOut: ~audioBus_ex_2d3]); + p.play; + + 1.5.wait; + x.release; + s.stopRecording; +}.fork +) + + +:: + + diff --git a/HelpSource/Tutorials/Other_event_and_pattern_shortcuts.schelp b/HelpSource/Tutorials/Other_event_and_pattern_shortcuts.schelp new file mode 100644 index 0000000..7384a3d --- /dev/null +++ b/HelpSource/Tutorials/Other_event_and_pattern_shortcuts.schelp @@ -0,0 +1,221 @@ + + +TITLE::Other event and patterns shortcuts +summary::various shortcut writings for events and patterns +categories:: Libraries>miSCellaneous>Event and pattern shortcuts +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/EventShortcuts, Tutorials/PLx_and_live_coding_with_Strings + +DESCRIPTION:: + +Apart from the class EventShortcuts itself, which handles bookkeeping of shortcut dictionaries, miSCellaneous lib includes some additional shortcut methods for generation and playing of events and different types of event patterns from SequenceableCollections. These methods support functional conventions for reference. See also link::Tutorials/PLx_and_live_coding_with_Strings::. + + +SECTION::1.) Event shortcuts + +subsection::1a: Event methods + +link::Classes/Event#-on:: + +link::Classes/Event#-off:: + + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// start default synth + +x = ().on + + +// release with 3 seconds releaseTime + +x.off(3) + + +// with EventShortcuts turned on this gives a quick way to run synths, +// here default synth with replacements 'n' -> 'note' and 'd' -> 'dur'. + + +EventShortcuts.makeCurrent(\default).on + +(n: [0, 4, 7, 12], d: 3).on + + +// define SynthDef + +SynthDef(\x, { |out = 0, freq = 440, amp = 0.05| Out.ar(0, SinOsc.ar(freq, 0, amp) * EnvGate.new) }).add + + +// run synth, audible beats with equal temperature, pitches given as notes ('n') + +(i: \x, n: [0, 4, 7], d: 3).on + + +// not with just intonation, pitches given as frequencies ('f') + +(i: \x, f: (4..6) * 100, d: 3).on + +:: + + + +subsection::1b: Event-related methods defined for SequenceableCollections + +link::Classes/SequenceableCollection#-ev:: + +link::Classes/SequenceableCollection#-on:: + +code:: + +// define an array as event template +// references to prior keys can be written as environmental variables in Functions +// here: higher midinotes get shorter durations + +( +a = [ + m: { rrand(60, 100) }, // midinote + d: { ~m.linlin(60, 90, 3, 0.1) } // dur +] +) + +// suppose EventShortCuts are turned on +// make an Event and see its data, then play, try several times + +x = a.ev + +x.on + + +// same can be done in one, try several times + +a.on + + +:: + + + +SECTION::2.) Event-pattern-related methods defined for SequenceableCollections + +link::Classes/SequenceableCollection#-pa:: + +link::Classes/SequenceableCollection#-p:: + +link::Classes/SequenceableCollection#-pm:: + +link::Classes/SequenceableCollection#-pma:: + +link::Classes/SequenceableCollection#-pbf:: + + +link::Classes/SequenceableCollection#-pp:: + +link::Classes/SequenceableCollection#-ppm:: + +link::Classes/SequenceableCollection#-ppma:: + +link::Classes/SequenceableCollection#-ppbf:: + + +code:: + +// use reference convention with Functions +// make an array of patternpairs to be used in different event pattern types + +( +a = [ + m: Pwhite(60, 80, 30), // midinote + d: { (~m > 70).if { 2 }{ 1 }/8 } // dur +].pa +) + +Pbind(*a).play + +Pmono(\default, *a).play + + + +// define Pbind and play on different channels + +( +p = [ + m: Pwhite(60, 80, 100), + d: { (~m > 70).if { 2 }{ 1 }/8 } +].p +) + +Pbindf(p, \p, -1).play(quant: 1/4) // \p for pan + +Pbindf(p, \p, 1).play(quant: 1/4) + + + +// same with Pmono ... + +( +[ + m: Pwhite(60, 80, 30), + d: { (~m > 70).if { 2 }{ 1 }/8 } +].pm(\default) +) + +Pbindf(p, \p, -1).play(quant: 1/4) + +Pbindf(p, \p, 1).play(quant: 1/4) + + + +// ... and PmonoArtic + +( +p = [ + m: Pwhite(60, 80, 100), + d: { (~m > 70).if { 2 }{ 1 }/8 }, + l: Pwhite(0.1, 1.5) // legato +].pma(\default) +) + +Pbindf(p, \p, -1).play(quant: 1/4) + +Pbindf(p, \p, 1).play(quant: 1/4) + + + +// analogous definition with Pbindef +// example different as Pbindef is pattern and player in one + +( +p = [ + m: Pwhite(60, 80, 100), + d: { (~m > 70).if { 2 }{ 1 }/8 } +].pbf(\x) +) + +Pbindef(\x, \p, -1).play + +Pbindef(\x, \p, 1) + +Pbindef(\x).clear + + + +// immediately play Pbind +// also play Pmono, PmonoArtic and Pbindef directly with methods ppm, ppma and ppbdf + +( +[ + m: Pwhite(60, 80, 30), + d: { (~m > 70).if { 2 }{ 1 }/8 } +].pp +) + +:: + + + + diff --git a/HelpSource/Tutorials/PLx_and_live_coding_with_Strings.schelp b/HelpSource/Tutorials/PLx_and_live_coding_with_Strings.schelp new file mode 100644 index 0000000..4c310cf --- /dev/null +++ b/HelpSource/Tutorials/PLx_and_live_coding_with_Strings.schelp @@ -0,0 +1,773 @@ +TITLE::PLx and live coding with Strings +summary::PLx patterns as placeholders for sequencing with letters +categories:: Libraries>miSCellaneous>PLx suite +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/PLx_suite, Classes/PsymNilSafe, Classes/PLbindef, Classes/PLbindefPar, Classes/EventShortcuts + + +DESCRIPTION:: + +Strings and Chars as high-level representations for musical objects can be used for sequencing with very condensed syntax. This is already possible with standard patterns like Pseq etc. – PLx list patterns fit this concept as their referenced Arrays/Strings can be replaced on the fly. Examples below also use EventShortcuts to minimize typing. + +warning:: +Sequencing with infinite Patterns/Streams has always the potential of hangs. E.g. Psym hangs if all referenced pattern return nil (SC 3.7.2). Here convenience method link::Classes/Pattern#-symplay:: is suggested: it employs PsymNilSafe, its method strong::embedInStream:: performs a check like in James Harkins' PnNilSafe from ddwPatterns quark (which can't be used directly this case). strong::symplay:: thus avoids hangs of that type, see link::#Ex.2b#Ex.2b) Embedding with continuation::. +:: + + +anchor::above:: +code:: +( +s = Server.local; +Server.default = s; +s.boot; +) + +( +// synthdefs to play with, use of EventShortcuts + +SynthDef(\noise, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + + +SynthDef(\saw, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + +EventShortcuts.on; +) +:: + + +SECTION::Ex.1) Straight usage with finite Patterns and Events + +code:: +( +// use EventShortcuts + +EventShortcuts.on; +EventShortcuts.postAll; + +// base Pbind + +~x = Pbind(\d, 0.1, \i, \sin); + +// chars for the string, event patterns or events + +~a = Pbind(\m, Pseries(60, 2, 4)) <> ~x; +~b = Pbind(\m, Pseries(80, -2, 8)) <> ~x; +~c = (i: \saw, m: [95, 96, 97], d: 0.8); + +// define sequence + +~p = "aab" +) + +// symplay wraps into a PsymNilSafe +// PLseq defaults to repeats = inf and refers to 'p' in current Environment, +// thus the String "aab", the EventStreamPlayer should also get a name for start/stop, +// in this case we take the same letter (p) as interpreter variable + +p = PLseq(\p).symplay + + +// replace String of PLseq + +~p = "aacb" + + +// use of basic String operations + +~p = ~p ++ "cc" + +~p = ~p.reverse + + +( +// new char and sequence + +~d = Pbind(\m, Pwhite(60, 90, 2), \i, \noise) <> ~x; +~p = "adadcb"; +) + +// replace String + +~p = "bbcbcad" + + +// new chars +// the Function as first arg of Pseries is evaluated with every embedding, +// thus movements up and down start on different pitches + +( +~a = Pbind(\m, Pseries({ rrand(60, 75) }, 7, 4)) <> ~x; +~b = Pbind(\m, Pseries({ rrand(85, 95) }, -5, 8)) <> ~x; +~c = Pbind(\i, \noise, \m, Pn((95..100), 2)) <> ~x +) + + +// modify ~b + +~b = Pbind(\i, PLrand([\sin, \saw])) <> ~b; + + +// modify list, loop goes on +// evaluate several times, compare sound and posted String + +~p = ~p.scramble + +p.stop +:: + + + + +SECTION::Ex.2) Repeated embedding + +Control of embedding resp. the number of Events, that one Patterns should produce when played, is a subtle topic. A basic distinction is whether an embedded sequence should be produced with desired behaviour from begin to end (2a) or it should be paused and resumed (2b). The latter is the classical behaviour of Streams, but it can be mimiced with PSx stream patterns. In any case embedding can be done with varying length, e.g. by defined sequences or by interaction. + + +subsection::2a) Embedding without continuation + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#above#above::. + +code:: +( +// base Pbinds +~x = Pbind(\d, 0.15, \i, \sin, \rel, 1.5, \a, 0.02); +~y = Pbind(\d, Pn(0.9, 1), \i, \saw, \att, 0.8, \rel, 4, \a, 0.006); + +// variable for repeats arg +~ar = 4; + +// descending sequence, note the repeats arg: as with the start arg +// the Function is evaluated with every embedding, +// ~ar can be a Stream or a value +~a = Pbind(\m, Pseries({ rrand(75.0, 95) }, -7, { ~ar.next })) <> ~x; + +// chords without octave doubling +~b = Pbind(\m, Pfunc { { [48, 60, 72].choose } ! 9 + (0..12).scramble.drop(3) }) <> ~y; + +// define sequence +~p = "ba" +) + + +p = PLseq(\p).symplay + +// change to other repeats number + +~ar = 6 + +// make it a sequence with a Stream + +~ar = PLseq([2, 2, 4]).asStream // or shorter: PLseq([2, 2, 4]).iter + + +// go back to num and change String + +~ar = 3 + +~p = "baaa" + +~p = "baabaaaa" + + +p.stop +:: + + +anchor::Ex.2b:: +subsection::Ex.2b) Embedding with continuation + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#above#above::. + +code:: +// This can be done by feeding a stream into a pattern, either directly or with PSx + +( +// base Pbind +~x = Pbind(\d, 0.2, \rel, 0.5, \a, 0.03); + +// Streams to be continued + +~as = (Pbind(\m, Pn(Pseries(60, 1, 16)), \i, \saw) <> ~x).asStream; +~bs = (Pbind(\m, Pn(Pseries(90, -1, 16)), \i, \sin) <> ~x).asStream; + +// variable for repeats args +~ar = 4; +~br = 4; + +// for getting next values of an event stream we must pass an empty event as arg '.next(())' +~a = Pfuncn({ ~as.next(()) }, { ~ar.next }); +~b = Pfuncn({ ~bs.next(()) }, { ~br.next }); + +// define sequence +~p = "ab" +) + + +p = PLseq(\p).symplay + + +// change repeats + +~ar = 2; +~br = 1; + + +// this causes ~a to produce nils, only ~b still returns events + +~ar = nil; + +// This stops the player. +// Note that this kind of nil-detection works because 'symplay' employs PsymNilSafe. +// A construct like Psym(Pseq("ab", inf), ...).play would hang in that case + +~br = nil; + +// Note that this is different from the case, when the dictionary's key itself is nil. +// Then we get silent events, that also would't cause a hang with Psym(Pseq("ab", inf), ...).play + + +// evaluate above code starting from ~x = ... again and run + +p = PLseq(\p).trace.symplay + +// now we get a rest event + +~a = nil + +// player keeps running silently, stop explicitely + +~b = nil + +p.stop + + +// same as above written with PSx stream patterns + +( +// base Pbind +~x = Pbind(\d, 0.2, \rel, 0.5, \a, 0.03); + +// variable for repeats args +~ar = 4; +~br = 4; + +~a = PS(Pbind(\m, Pn(Pseries(60, 1, 16)), \i, \saw) <> ~x, { ~ar.next }); +~b = PS(Pbind(\m, Pn(Pseries(90, -1, 16)), \i, \sin) <> ~x, { ~br.next }); + +// define sequence +~p = "ab" +) + + +p = PLseq(\p).symplay + +// change repeats + +~ar = 2; +~br = 1; + +p.stop; +:: + + + + + + + +SECTION::Ex.3) Parallel embedding + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#above#above::. + +code:: +// This can e.g. be done with Ppar, Ptuple or Pspawner, which is most flexible. +// There's a tiny isssue here in combination with EventShortcuts, duration keys +// should be in full length (You could apply method 'eventShortcuts' inside Ppar, +// but that's even more typing in that case, so we just write 'dur' instead of 'd'). + +( +// base Pbind + +~x = Pbind(\dur, 0.1, \i, \sin); +~y = Pbind(\dur, 0.05, \i, \sin); + +// chars for the String, event patterns or events + +~a = Pbind(\m, Pseries({ rrand(60.0, 65) }, 1, 8)) <> ~x; +~b = Pbind(\m, Pseries({ rrand(85.0, 95) }, -1, 8)) <> ~y; + +~c = Ppar([~a, ~b]); + +~d = (i: \saw, m: [95, 96, 97], d: 0.8); + +// define sequence + +~p = "accd" +) + + +p = PLseq(\p).symplay + +// equivalent with Pspawner + +~c = Pspawner { |sp| sp.par(~a); sp.par(~b) }; + + +// with Pspawner you have precise control over embedding of subsequences + +~c = Pspawner { |sp| sp.par(~a); 4.do { sp.par(~b) } }; + + +~e = Pspawner { |sp| sp.par(~a); 3.do { sp.seq(~b) } }; + +~p = "acde" + +p.stop +:: + + + +SECTION::Ex.4) Use of other PLx list patterns + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#above#above::. + +code:: +// We can keep the String constant and switch to different PLx list patterns. + +( +// base Pbind + +~x = Pbind(\d, 0.1, \i, \saw); +~y = Pbind(\d, 0.2, \i, \sin); + +// chars for the String, event patterns or events + +~a = Pbind(\m, Pseries(60, Pwhite(1.0, 7.0), 4)) <> ~x; +~b = Pbind(\m, Pseries(80, Pwhite(1.0, 7.0), 4)) <> ~y; + +~c = ~x <> ~b; +~d = ~y <> ~a; + +~e = Pbind(\i, \noise, \m, Pn(70, 2)) <> ~x; + +// define sequence + +~p = "abcde" +) + + +// we need another proxy in that case, take general PL + +~l = PLseq(\p); + +p = PL(\l).symplay; + + +// scramble sequence and keep + +~l = PLshuf(\p); + + +// scramble with every loop + +~l = PLshufn(\p); + + + +// weighted random + +~l = PLwrand(\p, [4, 1, 3, 1, 1]/10); + +p.stop; +:: + + + + + +SECTION::Ex.5) PLbindef and PLbindefPar + + +High-level control of Strings can be combined with replacing key streams with PLbindef/PLbindefPar. + +note:: +You should always do cleanup with link::Classes/PLbindef#-remove:: / link::Classes/PLbindefPar#-remove:: or link::Classes/Pdef#-removeAll:: after finishing the examples (see notes in link::Classes/PLbindef:: / link::Classes/PLbindefPar::). +:: + + +subsection::Ex.5a) PLbindef + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#above#above::. + +code:: +( +// base PLbindef, continued embedding with PS as in Ex. 2b + +~x = PS(PLbindef(\y, \dur, 0.1, \i, \noise, \rq, 0.5, \att, 0.05, \rel, 0.1, \a, 0.05)); + +// chars for the String, event patterns or events + +~a = Pbind(\m, Pn(75, 1)) <> ~x; +~b = Pbind(\m, Pn(80, 1)) <> ~x; + +~c = Ppar([~a, ~b]); + +// define sequence + +~p = "ab" +) + +p = PLseq(\p).symplay + + +// update PLbindef's rq and amplitude with patterns + +~y.rq = PLseq((100..1).mirror / 1000) + +~y.a = PLseq((20..80).mirror / 1000) + + +// update String + +~p = "c" + +~p = "ababccc" + + +// stop and cleanup + +p.stop + +~y.remove +:: + + + +subsection::Ex.5b) PLbindefPar + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#above#above::. + +code:: +( +// data base for two PLbindefPars, continued embedding with PS as in Ex. 2b + +~w = [\dur, 0.1, \i, \noise, \rq, 0.5, \att, 0.05, \rel, 0.1, \a, 0.02]; + +~chord = (46, 53..95); + +~a = PS(PLbindefPar(\u, 7, \m, ~chord, *~w), 1); +~b = PS(PLbindefPar(\v, 7, \m, ~chord + 2, *~w), 1); + +// define sequence + +~p = "ab" +) + +p = PLseq(\p).symplay + + +~u.rq = 0.005 + +~v.i = \saw + + +// evolving changes + +~u.rq = PLseq((100, 95..5).mirror / 1000) + +~v.a = Pseg(PLseq([0.01, 0.04]), Pwhite(4, 7)) + + +// change sequence per String + +~p = "aabb" + +~p = "aabbabab" + +~p = "aabbcababc" + +~p = "aaaab" + + +// fade out + +~v.a = Pseg(Pseq([0.02, 0]), 20) + +~u.a = Pseg(Pseq([0.02, 0]), 20) + + +// stop and cleanup + +( +p.stop; +~u.remove; +~v.remove; +) +:: + + +SECTION::Ex.6) String sequencing with PbindFx + +Control with Strings can be thought in many ways. With effects one can e.g. use different Strings for src and fx sequencing. + +anchor::last:: +subsection::Ex.6a) PbindFx + +code:: +// boot server with extended resources for PbindFx + +( +s.options.numPrivateAudioBusChannels = 1024; +s.options.memSize = 8192 * 16; +s.reboot; + +// fx synths + +SynthDef(\resample, { |out = 0, in, mix = 1, amp = 1, + resampleRate = 22050, lagTime = 1| + var sig, inSig = In.ar(in, 2); + sig = Latch.ar(inSig, Impulse.ar(resampleRate)); // resampling + // lag in milliseconds for smoothing + sig = sig.lag(lagTime * 0.001); + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000, + cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = RLPF.ar( + inSig, + LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi), + rq, + amp + ).softclip; + Out.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + + +// src synths + +SynthDef(\noise, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\saw, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + + +// prepare EventShortcuts for additional keys + +EventShortcuts.addOnBase(\default, \fxExs, ( + dec: \decayTime, + cd: \cleanupDelay, + cf: \cutOffMoveFreq, + fxo: \fxOrder, + rs: \resampleRate +), true); + +EventShortcuts.makeCurrent(\fxExs); + +EventShortcuts.on; +) + + +( +// base Pbind +// PbindFx's fxOrder (short: fxo) syntax employed by Symbol mapping: +// u: no fx, x: resample, y: wah, z: resample and wah in sequence + +~r = Pbind( + \fxo, Psym(PLseq(\fx), (u:0, x:1, y:2, z:[1, 2])), + \a, 0.07, + \att, 0.01, + \rel, 0.3, + \cd, Pkey(\att)+ Pkey(\rel) + 0.1 +); + +// PS to embed + +~a = PS(Pbind(\i, \saw, \d, 0.1, \m, PLseq([60, 60, 60, 62])) <> ~r, 1); + +~b = PS(Pbind( + \i, \noise, + \d, 0.2, + \m, PLseq([Pwhite(41.0, 50),Pwhite(71.0, 80)]), + \rq, 0.01 +) <> ~r, 1); + +// no cleanupDelay defaults for fxs as they don't delay +q = PbindFx(PsymNilSafe(PLseq(\p)), [ + \fx, \resample, + \mix, 0.3, + \rs, Pwhite(200, 500), + \a, 1 + ],[ + \fx, \wah, + \mix, 0.8, + \cf, Pwhite(0.5, 5), + \a, 0.7 +]); +) + +// start instrument sequence with no fx + +( +~fx = "u"; +~p = "aab"; +p = q.play; +) + +// fx sequences + +~fx = "uuxy" + +~fx = "uyuxzzzz" + + +~p = "b" + +p.stop +:: + + +subsection::Ex.6b) PbindFx and PLbindef + +Use SynthDefs from link::Tutorials/PLx_and_live_coding_with_Strings#last#last example::. + +code:: +// There's more fine-tuned control if we can replace key streams also + +( +// base pairs for PLbindef + +~r = [ + \fxo, Psym(PLseq(\fx), (u:0, x:1, y:2, z:[1, 2])), + \a, 0.07, + \att, 0.01, + \rel, 0.3, + \cd, Pkey(\att) + Pkey(\rel) + 0.001 +]; + +// PS to embed + +~a = PS(PLbindef(\aa, \i, \saw, \d, 0.1, \m, PLseq([60, 60, 60, 62]), *~r), 1); + +~b = PS(PLbindef(\bb, + \i, \noise, + \d, 0.2, + \m, PLseq([Pwhite(41.0, 50),Pwhite(71.0, 80)]), + \rq, 0.1, + *~r +), 1); + +// as we have defined fx chars 'x' and 'y' above, +// choose related names 'xx' and'yy' for PLbindefs + +q = PbindFx(PsymNilSafe(PLseq(\p)), + PLbindef(\xx, + \fx, \resample, + \mix, 0.3, + \rs, Pwhite(200, 500), + \a, 1 + ), + PLbindef(\yy, + \fx, \wah, + \mix, 0.8, + \cf, Pwhite(0.5, 5), + \a, 0.7 + ) +); +) + +// start with no fxs + +( +~fx = "u"; +~p = "aab"; +p = q.play; +) + +// fx sequence + +~fx = "uuxy" + + +// midinote for ~a and ~b + +~aa.m = [50, 52] + +~bb.m = Pwhite(80, 96) + + + +// switch to single fx resample for testing changes of its control streams +// resample, test rate + +~fx = "x" + +~xx.rs = Pwhite(1000, 3000) + + +// same with wah + +~fx = "y" + +~yy.cf = 3 + + +// src changes + +~aa.rel = 0.1 + +~bb.rel = 0.5 + + +// further playing + +~fx = "xxy" + +~p = "aabaabaaaabb" + + +~aa.m = [38, 40] + +~bb.rq = 0.7 + +~fx = "z" + + +// fade out + +~aa.a = Pseg(Pseq([0.04, 0]), 20) + +~bb.a = Pseg(Pseq([0.04, 0]), 20) + + +// cleanup + +p.stop + +Pdef.removeAll +:: diff --git a/HelpSource/Tutorials/PLx_suite.schelp b/HelpSource/Tutorials/PLx_suite.schelp new file mode 100644 index 0000000..04576b3 --- /dev/null +++ b/HelpSource/Tutorials/PLx_suite.schelp @@ -0,0 +1,577 @@ +TITLE::PLx suite +summary::dynamic scope Pattern variants +categories:: Libraries>miSCellaneous>PLx suite, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Tutorials/Event_patterns_and_Functions, Classes/VarGui, Tutorials/VarGui_shortcut_builds, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Tutorials/PLx_and_live_coding_with_Strings + + +DESCRIPTION:: + +Environmental variables within functions can act as placeholders for values, but also Patterns itself. So Patterns including functional code (e.g. Pfunc, Plazy, Pcollect) can, thanks to dynamic scoping, turn into different Streams, depending on the environment where streamifying happens ( link::Tutorials/Event_patterns_and_Functions:: ). This can be used for getting a whole parametrized family of Streams / EventStreamPlayers from a single pattern definition. Other applications are on-the-fly replacements and gui control of parameters of Pbinds / EventStreamPlayers with link::Classes/VarGui:: . Nevertheless constructs with Plazy, Pfunc etc. require some redundant typing which is saved by PLx Patterns (lazy evaluation). They are either plain wrapper classes or include variant implementations for the most common pattern types and deliver a more or less unified way for the described kind of placeholding. + +Unification however can only be approximated as Patterns, even those of one type (e.g. ListPatterns), are defining different behaviour: not all inputs of a source pattern x can be dynamically updated (e.g. the start of a Pseries), not all of them are allowed to be Patterns itself. Implementation and usage may differ a bit from class to class. If there is no PLx implementation of a source Pattern class you can use PL as a general pattern placeholder input, see link::Classes/PL:: help file for an example. link::Classes/PLbindef:: and link::Classes/PLbindefPar:: allow key stream replacements in shortcut object prototyping syntax. + + + +note:: +PL follows a paradigm of immediate replacement. There are cases though where you might prefer to finish streams or substreams before replacement, especially when syncing comes into play, for these options consider link::Classes/PLn:: and the strong::cutItems:: arg of PLx list patterns. +:: +warning:: +Feeding a looped process with an invalid input has always the potential to lead to hangs. See link::Classes/PsymNilSafe:: and link::Tutorials/PLx_and_live_coding_with_Strings:: for some remarks on that. +:: + +SECTION::PLx pattern classes + +subsection::value and event patterns + +link::Classes/PL::, link::Classes/PLn::, link::Classes/PLseq::, link::Classes/PLser::, link::Classes/PLrand::, link::Classes/PLwrand::, link::Classes/PLshuf::, link::Classes/PLshufn::, link::Classes/PLslide::, link::Classes/PLtuple::, link::Classes/PLwalk::, link::Classes/PLswitch::, link::Classes/PLswitch1:: + +subsection::value patterns + +link::Classes/PLwhite::, link::Classes/PLlprand::, link::Classes/PLhprand::, link::Classes/PLmeanrand::, link::Classes/PLbrown::, link::Classes/PLgbrown::, link::Classes/PLseries::, link::Classes/PLgeom::, link::Classes/PLbeta::, link::Classes/PLcauchy::, link::Classes/PLgauss::, link::Classes/PLpoisson::, link::Classes/PLexprand:: + +subsection::filter patterns + +link::Classes/PLnaryop::, link::Classes/PLnaryFunc::, link::Classes/PLIdev:: + +subsection::subclasses of Pdef + +link::Classes/PLbindef::, link::Classes/PLbindefPar:: + + + +EXAMPLES:: + +anchor::Ex. 1a:: +subsection::Ex. 1a: ListPatterns placeholder constructs with Plazy + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + +// This is how dynamic scope placeholding of a ListPattern +// could be done with Plazy, +// Pn defaults to repeats = inf. + +( +p = Pn(Plazy { Pseq(~a, 1) }); + +~a = (60..70); + +x = Pbind( + \midinote, p, + \dur, 0.2 +).play; +) + + +// First drawback: replacing of a new list doesn't have an immediate effect +// as the old list is looped through before. + +// Try evaluating this before the end of the original loop. + +~a = (75..84) ++ Pseq([85,86], 10); + + +// Second drawback: replacing of a single pattern element, +// which corresponds to a stream just being embedded, +// doesn't have an immediate effect +// as this embedding is finished before. + +// Try evaluating this during the trill, it doesn't have an +// effect before the next loop. + +~a[10] = 91; + +x.stop; + +:: + +Similar placeholder constructs with Pcollect and Pfunc have similar drawbacks concerning replacement. However, this type of "delayed replacement" might be wanted in some cases and is also possible with PLx patterns, see link::Classes/PLn:: and the strong::cutItems:: arg of PLx list patterns. + + + +anchor::Ex. 1b:: +subsection::Ex. 1b: PLx implementation of ListPatterns + +PLx Patterns take symbols as input. Derived Streams get the values of the Environment of streamification. + + +code:: + +( +p = Pbind( + \midinote, PLseq(\a), + \dur, 0.2 +); + +~a = (60..70); + +y = p.play; +) + + +// replacement of the whole list has an immediate effect now, +// with Pseq the loop starts with the new list + +~a = (75..84) ++ Pseq([85,86], 10); + + +// replacing a single element also has an immediate effect, +// (as PLseq's cutItems arg defaults to true), +// try evaluating during the trill + +~a[10] = 91; + +y.stop; + + +// PLx ListPattern implementations can also act as +// ordinary ListPatterns if args are not Symbols. +// Difference: repeats arg defaults to inf, +// so you save typing in this case, +// but don't apply .all to Streams derived from such Patterns ! + +( +x = Pbind( + \midinote, PLseq((60..70)), + \dur, 0.2 +).play; +) + +x.stop; + +:: + +anchor::Ex. 1c:: +subsection::Ex. 1c: PLx implementation of Non-ListPatterns + + +code:: + +// an explicit definition with Plazy + +p = Pwhite(Pn(Plazy { ~lo }), Pn(Plazy { ~hi }), { ~r }); + + +// similarily done implicitely by PLwhite + +q = PLwhite(\lo, \hi, \r); + + +// streamify in envir + +e = (lo: 60, hi: 90, r: 30); + +e.use { q.asStream.all }; + + +// reset repeats to inf and streamify again + +e.use { ~r = inf; x = Pbind(\midinote, q, \dur, 0.2).play }; + + +// replace lower bound by pattern + +e.lo = PLseq([60, 90]); + +x.stop; + +:: + + +anchor::Ex. 1d:: +subsection::Ex. 1d: Plain PL + +A general placeholder that can be updated after instantiation. +Its repeats arg defaults to inf. + +code:: + +PL(\a, \r); + +// roughly equivalent to + +Pn(Plazy { ~a }, { ~r }); + + +e = (a: Pseq((60, 62.5..80))); + +e.use { x = Pbind(\midinote, PL(\a), \dur, 0.1).play } + + +// note that with this replacement new scrambles are chosen +// repeatedly because Pshuf's repeats arg defaults to 1. + +e.a = Pshuf((80, 78.5..65)); + + +// fixed reordering + +e.a = Pshuf((80, 78.5..65), inf); + +e.a = PLshuf((80, 78.5..65)); + + +x.stop; + +:: + +PL can also be used with Patterns which don't have a PLx implementation. +See link::Classes/PL:: for an example. + + + +anchor::Ex. 2:: +subsection::Ex. 2: Playing in different Environments + +code:: + +// Pbind to be streamified differently in different environments + +( +p = Pbind( + \midinote, PLseq(\a), + \dur, PL(\d) +); + +e = (a: (67..72), d: 0.1); +f = (a: (85..90), d: 0.2); +) + + +// start in sync or individually + +x = e.use { p.play(quant: 0.2) }; +y = f.use { p.play(quant: 0.2) }; + + +// replacement of array elements ... + +e.a[0] = 95; +f.a[0] = [75, 79]; + + +// ... which may also be Patterns + +f.a[0] = Pseq([75, 79], 3); + + +// replacing the whole array + +f.a = (83..80); + +f.a = (79..75) +.t [0, 3.5]; + +e.a = [Pseq([63, 65.5], 4), 85, 87]; + +x.stop; +y.stop; + +:: + + + +anchor::Ex. 3:: +subsection::Ex. 3: Use with VarGui + +code:: + +// basic form of a step sequencer (amp defaults to 0 in associated global ControlSpec) + +( +\default.pVarGui( + ctrBefore: [\a, [0, 6, \lin, 1, 3] ! 8], + pBefore: [\degree, PLseq(\a) ] +).gui; +) + +:: + + +See link::Classes/VarGui:: and link::Tutorials/VarGui_shortcut_builds:: for further examples. + + + + +anchor::Ex. 4:: +subsection::Ex. 4: The repeats arg + +PLx Patterns' repeats arg defaults to inf. This makes sense in situations where you want to go on replacing items on the fly. If a PLx Patterns is itself enclosed you may want to set it to a different value. Anyway the resulting number of repeats is the product of outer and inner repeats. + +code:: + +// PL(\a) defaults to repeats = inf +// Pshuf defaults to repeats = 1, is embedded repeatedly and +// so it continues producing new permutations (like Pshufn) + +( +p = Pbind( + \midinote, PL(\a), + \dur, 0.15 +); + +~a = Pshuf((60..63)); +) + + +x = p.play; + + +// same effect, but this is normal Pshufn behaviour + +~a = Pshufn((60..63)); +~a = Pshufn((60..63), inf); + +x.stop; + + +// PL(\a, 2) demands inner repeats = inf for endless running + +( +p = Pbind( + \midinote, PL(\a, 2), + \dur, 0.15 +); + +~a = Pshuf((60..63), inf); +) + +// now normal Pshuf behaviour + +x = p.play; + + +// same achieved with PLshuf((60..63)) as it defaults to repeats = inf + +~a = PLshuf((60..63)); + + +// stop with a Pseq which defaults to repeats = 1, played twice because of PL(\a, 2) + +~a = Pseq((70..65)); + + +:: + + +anchor::Ex. 5a:: +subsection::Ex. 5a: Updating input of N-ary operators + +One may want to have the choice to update inputs of N-ary operators applied to Patterns too. A common case is clipping. Say you have a Pcauchy pattern (distribution with a relatively high number of outliers) and want to dynamically change its mean value and clip bounds. + + +code:: + +( +p = Pbind( + \midinote, PLcauchy(\m, \s).collect(_.clip(~lo, ~hi)), + \dur, 0.1 +); +) + +// define the environment + +e = (m: 75, s: 1, lo: 60, hi: 90); + +e.use { x = p.play }; + +// update upper bound to mean value + +e.hi = 75; + +x.stop; + + +// above pitch pattern could be written explicitely too with Pnaryop + +Pnaryop(\clip, PLcauchy(\m, \s), [Pfunc { ~lo }, Pfunc { ~hi }]) + +// more powerful: PL allows updating with patterns + +Pnaryop(\clip, PLcauchy(\m, \s), [PL(\lo), PL(\hi)]) + +// even shorter: the PLnaryop class expands to the above + +PLnaryop(\clip, PLcauchy(\m, \s), [\lo, \hi]) + + +// In the simple case of updating clip bounds with values +// maybe one would rather use the version with collect. + +// But with Pnaryop you can pass a list of arbitrary patterns as arglist +// and with PLnaryop you can dynamically update with arbitrary patterns - +// both can be used for more differentiated control of clip bounds +// (or args of any other N-ary operator or Function). +// Also the source pattern can be replaced. + +( +p = Pbind( + \midinote, PLnaryop(\clip, \pat, [\lo, \hi]), + \dur, 0.1 +); +) + +// define the environment and play + +e = (pat: PLcauchy(\m, \s), m: 75, s: 1, lo: 60, hi: 90); + +e.use { x = p.play }; + + +// compare distributions + +e.pat = PLgauss(\m, \s); + + +// switch back to Cauchy with more outliers + +e.pat = PLcauchy(\m, \s); + + +// update bounds, lo bound 85 is mostly gone below, +// so nearly every second event has this midinote +// vice versa with hi bound 65 + +e.lo = PLseq([60, 85]); + +e.use { ~lo = 60; ~hi = PLseq([65, 90]) }; + + +// clipping to a window that loops through the distribution: +// values are taking more or less the wandering clip bounds if lo or hi, +// but are rather randomly distributed between clip bounds around the mean value + +e.use { ~lo = PLseq((50..95)); ~hi = ~lo + 10 }; + +x.stop; + +:: + +For replacing operators dynamically take PLnaryFunc with the operator wrapped into a Function. + + +anchor::Ex. 5b:: +subsection::Ex. 5b: Updating input of N-ary Functions + +Self-defined functions can be used as with PLnaryop. + + +code:: + +( +p = Pbind( + \midinote, PLnaryFunc(\f, \src, [\b, \c]), + \dur, 0.1 +); +) + +// define Environment + +( +e = (); + +e.src = Pstutter(3, PLseq((60, 70..90))); +e.b = PLseq((0..2)); +e.c = 0; + +e.f = { |x,y,z| x + y + z }; +) + + +// run + +e.use { x = p.play }; + + +// replace function input + +e.b = PLseq((0..1)); + +e.c = [-5, 0]; + +e.c = PLseq([[-5, 0], [0, 3]]); + +e.b = PLshuf((0..3)); + + +// replace function + +e.f = { |x,y,z| x + (y * 1.2) + z }; + +e.f = { |x,y,z| x + y + (z * 1.7) }; + + +x.stop; + +:: + + +subsection::Ex. 6: PLbind / PLbindef + +code:: + +// start PLbindef, an special Environment of that name is created for setting + +p = PLbindef(\a, \midinote, 70).play + +// set in it + +~a.midinote = Pwhite(60, 80) + +~a.midinote = ~a.midinote + [0, 4] + +~a.dur = 0.25 + +// cleanup + +( +p.stop; +p.remove; +) + + +// PLbindef sprouts parallel processes +// start 4 in unisono + +p = PLbindefPar(\b, 4, \midinote, 60, \dur, 2, \amp, 0.03).play + +// set single streams + +~b[3].midinote = Pwhite(70, 70.5) + +~b[3].dur = 0.05 + + +~b[2].midinote = Pwhite(65.0, 67) + +~b[2].dur = 0.1 + + +// use method value for setting + +~b.([0, 1], \midinote, Pwhite(50, 60), \dur, 0.1) + + +// general setting, now we probably aren't in sync + +~b.dur = 2 + + +// reset syncs + +p.reset + + +// stop and cleanup + +( +p.stop; +p.remove; +) +:: + + diff --git a/HelpSource/Tutorials/PSx_stream_patterns.schelp b/HelpSource/Tutorials/PSx_stream_patterns.schelp new file mode 100644 index 0000000..89d964a --- /dev/null +++ b/HelpSource/Tutorials/PSx_stream_patterns.schelp @@ -0,0 +1,69 @@ + +TITLE::PSx stream patterns +summary::Pattern variants that have a state and can remember their last values +categories:: Libraries>miSCellaneous>PSx stream patterns, Streams-Patterns-Events +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/MemoRoutine, Classes/PS, Classes/PSdup, Classes/PSrecur, Classes/PSloop + + +DESCRIPTION:: + +In general Patterns are thought to have no state. They are defining models for the really generative objects, Streams, which respond to the method next that causes them to return a next value. So, in general, an arbitrary number of Streams might be derived from one Pattern, all behaving as defined by the latter. +However there are cases where it is comfortable to have objects that behave like Streams, e.g. resume from their last state if embedded, and at the same time still benefit from everything which is already implemented for Patterns. PSx stream patterns are an attempt to accomplish this. PSx patterns behave like Streams - they resume from last state when repeatedly embedded -, they remember their last value (or a number of last values) and they are real Patterns by subclassing, i.e. operators defined for Patterns can be applied. Internally they use Stream's subclass link::Classes/MemoRoutine:: which performs value buffering. + + +SECTION::PSx value and event pattern classes + +link::Classes/PS::, link::Classes/PSdup::, link::Classes/PSrecur::, link::Classes/PSloop:: + + +EXAMPLES:: + + +code:: + +( +p = Pseq([ + PS(Pseq((1..9), inf), 3), + PS((Pseries() + 1) * 100, Pseq([1,2,3], inf)) +], inf); + +q = p.asStream; + +q.nextN(50); +) + +// ATTENTION: + +// It is important to remember that, differing from normal +// Pattern convention, repeatedly applying .asStream to a +// PSx pattern or a Pattern that encloses a PSx doesn't cause a Stream to begin at the start. +// Every new Stream refers to the internally used and previously left off MemoRoutine. + + +p.asStream.nextN(5); + +p.asStream.nextN(10); + + +// For getting a totally new Stream you can reevaluate the Pattern definition or +// define the Pattern with a wrapping Function: + +( +a = { + Pseq([ + PS(Pseq((1..9), inf), 3), + PS((Pseries() + 1) * 100, Pseq([1,2,3], inf)) + ], inf); +}; + +b = a.value.asStream; + +b.nextN(50); +) + +a.value.asStream.nextN(5); + +a.value.asStream.nextN(10); + +:: + diff --git a/HelpSource/Tutorials/Sieves_and_Psieve_patterns.schelp b/HelpSource/Tutorials/Sieves_and_Psieve_patterns.schelp new file mode 100644 index 0000000..1959237 --- /dev/null +++ b/HelpSource/Tutorials/Sieves_and_Psieve_patterns.schelp @@ -0,0 +1,1347 @@ +TITLE::Sieves and Psieve patterns +summary::list building and sequencing based on Xenakis' sieves +categories:: Libraries>miSCellaneous>Sieves and Psieve Patterns, Streams-Patterns-Events>Sieves and Psieve Patterns +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/Sieve, Classes/Psieve, Classes/PSPdiv, Classes/PSVunion, Classes/PSVunion_i, Classes/PSVunion_o, Classes/PSVunion_oi, Classes/PSVsect, Classes/PSVsect_i, Classes/PSVsect_o, Classes/PSVsect_oi, Classes/PSVsymdif, Classes/PSVsymdif_i, Classes/PSVsymdif_o, Classes/PSVsymdif_oi, Classes/PSVdif, Classes/PSVdif_i, Classes/PSVdif_o, Classes/PSVdif_oi, Classes/PSVop, Classes/PSVop_i, Classes/PSVop_o, Classes/PSVop_oi + + +DESCRIPTION:: + +Iannis Xenakis proposed sieves as integer-based generators for rhythms, pitches and other musical parameters. For an overview of history and implementations, including his own development in Python, see Christopher Ariza's article link::#[3]::. + +This SC implementation comes in two variants, with the class Sieve and Psieve patterns. Both variants include the usual sieve operations, which are based on set theory and applied to integers: union, intersection, symmetric difference and difference (complement can be defined by difference). These operations are defined for an arbitrary number of arguments as well as binary operators (Sieve). Psieve as an abstract superclass of all sieve patterns integrates sieve sequences into the pattern framework whereas Sieve is defined for calculating sieves as lists, in other words Psieve patterns are the "lazy evaluation" variant of "eager evaluation" Sieve operations. Of course you can produce sieves as lists also with Psieve patterns but for calculating very large sieves beforehand you might want to prefer Sieve, as its operations are slightly faster. For using sieves in a realtime situation the overhead of Psieve patterns will mostly be irrelevant. + +Why sieves + patterns? Not only can the ouput of sieve calculations be used in enclosing patterns – e.g. for scaling or arbitrary mapping into the continous domain –, Sieve and Psieve patterns also accept Patterns (which must be defined to produce integers) themselves as input for sieve operations, which opens a wide field for experimentation – in the case of Psieve patterns this even allows realtime control of sieve parameters and/or sieve stream output, also the logical operations can be exchanged on the fly. In one regard this is a contradiction to Xenakis' idea of sieves as an "outside-time" structure, on the other hand Xenakis, as Roads pointed out (link::#[1]::, p.168), always tended to use generative procedures very freely and this also becomes explicit, when he describes "hyperbolae" (transformations) of sieves and suggests "... transformations of the logical operations in some fashion, using the laws of logic and mathematics, or arbitrarily." (link::#[3]::, p.66). Patterns involve a wide range of such possibilities and provide a comfortable interface to be applied dynamically. + +Psieve patterns as well as Sieves can work in two modes, regarding sieves as sequences (resp. lists) of 'intervals' with an offset, or as 'points', meaning the ascending numbers itself (the wording of 'sums' and 'differences' would also be nearby, but here 'difference' is already used for set operations, so I leaned on Xenakis' terms). For efficiency reasons only one representation of a Sieve is current at a time, the default result mode is 'points'. However all operations exist in alternative result mode variants and of course Sieves can also be converted anytime. For calculus of Sieves there exist corresponding binary operators as shortcuts. + +Characteristics of sieves are closely bound to relations of numbers by prime factors, roughly said: more complexity and longer periodicity is following from merging moduls that have fewer prime factors in common. However for the sake of keeping classes light-weight, dealing with period lengths etc. is not implemented within the sieve classes itself. See link::#[1]:: and link::#[3]:: for some number-theoretical considerations, you might also want to check Xenakis' original examples and hints. Useful integer operations (prime numbers, factoring) are contained in SC main and can help you to easily carry through your own experiments, some extensions of built-in lcm-algorithm are contained (link::#4b::). A thorough investigation of the symmetric structures generated is out of the scope of this package, however some observations on symmetry types (link::#3b::) and basic analysis tools are included (link::#3c::). Last but not least: plotting the intervals can give a good impression of sieve characteristics. +anchor::[1]:: +anchor::[2]:: +anchor::[3]:: +anchor::[4]:: + +subsection::References + +numberedList:: +## Xenakis, Iannis (1990). "Sieves" Perspectives of New Music 28(1): 58-78. +## Xenakis, Iannis (1992). Formalized Music. Hillsdale, NY: Pendragon Press, 2nd Revised edition. +## Ariza, Christopher (2005). "The Xenakis Sieve as Object: A New Model and a Complete Implementation" Computer Music Journal 29(2): 40-60. +## Roads, Curtis (2015). Composing Electronic Music. A New Aesthetic. Oxford University Press. + +:: + + +SECTION::1) The Sieve class + +subsection::1a) Basic generation from Integers, modes 'intervals' and 'points' + +code:: +// define a simple sieve with multiples of 3, 5 and 7, 0 is included +// as no limit is given, the result goes up to the default limit of 65536 +// per default result is given in mode 'points' + +a = Sieve.union(3, 5, 7) + + +// a limit is passed as Ref object as last arg + +a = Sieve.union(3, 5, 7, `30) + + +// convert to 'intervals': same Sieve object and new List that has one item less, +// the slot 'offset' is set accordingly (here it equals 0) +// the offset in mode 'points' is always nil + +a.toIntervals + + +// convert back + +a.toPoints + + +// access for arbitrary further use + +a.list + + +// generate a Sieve from an Integer, it contains one point + +a = 5.toSieve.dump; + +// it's interval representation is an empty list + +a.toIntervals.dump + + +// calculate with 'intervals' from the beginning + +Sieve.union_i(3, 5, 7, `30) +:: + + +subsection::1b) Generation from Patterns, Streams and Sieves + +code:: +// Instead of Integers producing their multiples you can pass Patterns or Streams. +// It's assumed that Patterns/Streams produce Integers interpreted as intervals +// (if it's defined to produce 'points' it can e.g. be wrapped into a Pdiff). + +Sieve.union(Pseq([1, 10], inf), 5, 7, `30) + +Sieve.union({ loop { rrand(1,10).yield } }.r, 5, 7, `30) + + +// compare with result from the pattern alone +// a union with one argument just returns its resulting elements. +// As pattern arguments are interpreted as intervals, 0 is included + +Sieve.union(Pseq([1, 10], inf), `30) + + +// a Sieve can itself be passed to generate a new one, +// the mode of the passed sieve is taken into account + +a = Sieve.union(5, 7, `30); + +Sieve.union(a, 3, `30) +:: + + +subsection::1c) Elementary sieve operations + +code:: +// beneath union: intersection, symmetric difference, difference +// note that order of arguments only plays a role with difference + + +// intersection: only integers produced by all generators +// symmetric difference: only integers produced by one of the generators +// difference: only integers produced by the first generator, but by none of the others + +// 'generator' here refers to allowed sieve operator args +// (Integers as modul generators, Patterns/Streams or Sieves itself) + + +// proof of concept, evaluate in order + +a = Sieve.union(3, 5, 6, `100) + +// collect all pairwise intersections + +( +b = Sieve.sect(3, 5, `100); // intersection with moduls: multiples of smallest common multiple +c = Sieve.sect(5, 6, `100); +d = Sieve.sect(3, 6, `100); // multiples of 6 itself +) + +// calculate the symmetric difference ... + +e = Sieve.symdif(3, 5, 6, `100) + + +// ... it equals the difference of a, b, c and d ... + +f = Sieve.dif(a, b, c, d, `100) + +e == f + +// ... which equals the difference of a and the union of b, c and d + +g = Sieve.dif(a, Sieve.union(b, c, d, `100)) + +e == g +:: + + +subsection::1d) Offset methods + +code:: +// for passing individual offsets there exist dedicated methods with suffixes '_o' and '_oi' +// offsets args are passed after the generating items + + +// one generating number with offset +// producing, mathematically spoken, a part of the residual class 2 modulo 3 + +Sieve.union_o(3, 2, `30) + + +// several generating numbers with offsets, passed pairwise + +Sieve.union_o(3, 2, 5, 1, 7, 4, `30) + +Sieve.union_oi(3, 2, 5, 1, 7, 4, `30) + + + +// the shift operation adds an offset, it changes the receiver + +a = Sieve.union(5, 7, `30); + +a.shift(100) + +a.shiftTo(0) + +// as operators + +a >> 100 + +a >>! 10 +:: + + +subsection::1e) Sieve operations defined as instance methods + +code:: +// all operations and shortcuts defined above can be applied to instances + +( +a = Sieve.union(3, 5, `1000); +b = Sieve.union(4, 7, `1000); +c = Sieve.union(6, 8, `1000); +) + +// Note that large periods are already resulting from simple combinations of +// elementary operations and few prime factors. + + +// by default plot shows intervals + +symdif(a, b, c).plot + +dif(a, b, c).plot +:: + + + +subsection::1f) Sieve operations defined as binary operators + +code:: +// instantiation with 'new': second arg limit doesn't need to be a Ref +( +a = Sieve(6, 60); +b = Sieve(8, 60); +) + +// union + +union(a,b) +a|b + +union_i(a,b) +a|*b + + +// intersection + +sect(a,b) +a&b + +sect_i(a,b) +a&*b + + +// symmetric difference + +symdif(a,b) +a--b + +symdif_i(a,b) +a--*b + + +// difference, only elementary operation where order plays a role + +dif(a,b) +a-b + +dif_i(a,b) +a-*b + +dif(b,a) +b-a + +dif_i(b,a) +b-*a + + +// Efficiency hint: for an operation with a number of args, especially with large Sieves, +// it is more efficient to use the core class or instance methods than to concatenate binary operators: +// doing the latter means stepping through the list/range with each binary operation +:: + +subsection::1g) Segments of Sieves + +code:: +// These operations result in new Sieve objects of mode 'points' + +a = Sieve.union(3, 5, 7, `30) + + +// lo bound + +a.segmentGreaterEqual(7) + +a >=! 7 + +a.segmentGreater(7) + +a >! 7 + + +// hi bound + +a.segmentLessEqual(10) + +a <=! 10 + +a.segmentLess(10) + +a =! [10, 20] + +a.segmentBetween(10, 20) + +a <>! [10, 20] +:: + + +subsection::1h) Conversion to Sieves from Arrays + +code:: +// Conversion from arbitrary SequenceableCollection to Sieve: +// per default it's assumed that receiver and result are thought to be in mode 'points' +// but source and target mode can be passed as args 'fromMode' and 'toMode' + +a = [1, 5, 17, 33, 37, 43, 57, 60, 61, 62, 63, 75, 89, 92, 97]; + +a.toSieve + + + +// define result mode, add offset + +a.toSieve(toMode: \intervals, addOffset: 100) + + +// define interval meaning of receiver +// default offset zero + +a.toSieve(\intervals) + + +// same with offset 1, abbreviations for mode selection + +a.toSieve(\i, \p, 1) + + + +// if Integers are regarded as points, they must be ascending ... + +a.reverse.toSieve + + +// ... but intervals can be descending ... + +a.reverse.toSieve(\i) + + +// ... however they must be positive + +(a.reverse ++ -1).toSieve(\i) + + +// It's possible to disable the checks preformed with conversion (flag 'withCheck'), +// but this only makes sense in a context where a large number of +// speed-critical conversions on well-prepared data has to be done. +// Otherwise it's always useful to perform those checks as +// sieve operations on wrong data (e.g. unordered lists) will fail or hang. +:: + + +subsection::1i) Copying and transformation of Sieves by arbitrary array operations + +code:: +// It would be possible to define Sieve as subclass of List but there exist many +// methods for List which don't make any sense for sieves, even worse: they can consequently +// result in disfunctionality of standard operations defined for Sieves as List subclasses. +// This could be overcome with additional checks for these standard operations, a bloating which +// can be avoided if we try to keep only "proper sieves" as Sieve objects, +// thus by default dedicated wrappers for arbitrary transformations include checks. + + +a = Sieve.union_o(3, 1, 7, 2, `30) + +// simple deep copy ... + +b = a.copy + + +// ... lists are equal but not identical + +a.list == b.list +a.list === b.list + +// as expected sieves are equal + +a == b + +// but also a converted Sieve is equal + +a == b.toPoints + + + +// mode (intervals) and offset are taken over from original Sieve +// new array is inserted and checked if it contains proper (ascending) integers + +a.copyWith([2, 17, 29, 31, 35, 53]) + +a.copyWith([2, 2, 3, 5, 1, 10]) + + + + +// if the receiver is of mode 'intervals', the array of above can be passed + +b = a.copy.toIntervals + +b.copyWith([2, 2, 3, 5, 1, 10]) + + + +// main workhorse for transformations, note that offset is kept while intervals reversed + +c = b.copyApplyTo(\reverse) + +c.toPoints + + +b.copyApplyTo(\mirror).plot + + +// as with method 'applyTo' arbitrary Functions can be passed + +b.copyApplyTo { |x| x * x * x ++ (1..10).mirror } + + +// partial application + +b.copyApplyTo(_ ++ [7, 5, 1]) +:: + + +SECTION::2) Psieve patterns + +subsection::2a) Basic generation from Integers, modes 'intervals' and 'points' + + +code:: +// Psieve patterns use the prefix PSV followed by the name of elementary +// sieve operations, as used with the Sieve class, and optional suffixes. +// In comparison with Sieve more arguments are taken, so +// the generating arguments and offsets are to be passed within an array. + + +PSVunion([3, 5, 7]).asStream.nextN(20) + +// intervals + +PSVunion_i([3, 5, 7]).asStream.nextN(20) + + +// other operations + +PSVsect([3, 5, 7]).asStream.nextN(20) + +PSVsymdif([3, 5, 7]).asStream.nextN(20) + +PSVdif([3, 5, 7]).asStream.nextN(20) + + + +// offsets, offsets + interval output + +PSVunion_o([3, 2, 5, 4]).asStream.nextN(20) + +PSVunion_oi([3, 2, 5, 4]).asStream.nextN(20) + + +PSVdif_o([3, 2, 5, 4]).asStream.nextN(20) + +PSVdif_oi([3, 2, 5, 4]).asStream.nextN(20) + +... + +// maxLength defines the maximum number of items - +// in case of a randomly generating item or a low summation limit +// the overall stream might have to end earlier. + +b = PSVunion([7, 17, 29], 30).asStream + +b.all + + +// if the summation limit is set, maxLength might not be reached + +c = PSVunion([7, 17, 29], 30, 100).asStream + +d = c.all + +d.size + +:: + + +subsection::2b) Generation from Patterns, Streams and Sieves + + +code:: +// distorted periodicity by union with random sieve + +a = ({ rrand(0, 1000) } ! 50).asSet.asArray.sort.toSieve + +PSVunion_i([4, 7, a]).asStream.nextN(100).plot + +// compare + +PSVunion_i([4, 7]).asStream.nextN(100).plot + + + +// distorted periodicity by union with random patterns + +PSVunion_i([4, 7, Pn(Pshuf([2, 5, 9])) ]).asStream.nextN(100).plot + +PSVunion_i([4, 7, Pwhite(3, 5) ]).asStream.nextN(100).plot +:: + + +subsection::2c) Sequencing logical operations + + +code:: +// This is done by PSVop patterns, which take a Symbol or a pattern of Symbols, +// refering to the elementary logical operators. +// The stream of operations is forwarded with every integer point, +// which has to be stepped through. + +// helper function for plotting + +p = { |x, n = 200| x.asStream.nextN(n).plot }; + + +// plain standard operations, all elementary PSV patterns can be written with PSVop + +PSVop([5, 9], \u).asStream.nextN(20) // union +PSVop([5, 9], \d).asStream.nextN(20) // difference +PSVop([5, 9], \sd).asStream.nextN(20) // symmetric difference + + +// some operator loops + +p.(PSVop_i([5, 9], Pseq([\u, \sd], inf))) +p.(PSVop_i([5, 9], Pseq([\u, \s], inf))) +p.(PSVop_i([5, 9], Pseq([\u, \d], inf))) +p.(PSVop_i([5, 9], Pseq([\u, \d, \sd], inf))) + + +// random operator changes + +p.(PSVop_i([5, 9], Pn(Pshuf([\u, \d])))) +p.(PSVop_i([5, 9], Prand([\u, \d], inf))) + + + +// change of difIndex: + +p.(PSVop_i([5, 2, 3], \d)) +p.(PSVop_i([5, 9], Prand([\u, \d], inf))) + + +// "subtract" from index 0: multiples of 5, not divided by 7, 9, and 12 + +PSVdif([5, 7, 9, 12]).asStream.nextN(30) + + +// same as intervals, plotted + +p.(PSVdif_i([5, 7, 9, 12])) + +// written with PSVop + +p.(PSVop_i([5, 7, 9, 12], \d, 0)) + + +// also changing the positions other than the first is equivalent + +p.(PSVdif_i([5, 7, 9, 12])) + +p.(PSVop_i([5, 12, 7, 9], \d, 0)) + + + +// but "subtracting" from another number is different + +p.(PSVdif_i([12, 9, 7, 5])) + + +// you can write the same with PSVop and difIndex without swapping the elements + +p.(PSVop_i([5, 12, 7, 9], \d, 1)) + + + +// you can generate more complicated periods by more refined series of difIndices ... + + +p.(PSVop_i([4, 7], \d, 0)) + + +p.(PSVop_i([4, 7], \d, PLseq([0, 0, 1]))) + +p.(PSVop_i([4, 7], \d, PLseq([0, 0, 1, 0, 0, 0, 1]))) + + +// ... or combination of dynamic operator changes and difIndex changes. +// difIndices are only forwarded when operator 'difference' is current + +p.(PSVop_i([4, 7], PLseq([\d, \d, \u]), PLseq([0, 0, 1]))) +:: + + + +subsection::2d) Using Sieves in other than Psieve patterns + +code:: +// Period lengths of intervals of basic Sieves are related to prime factors and +// least common multiples ([1] and [3] for a more detailled description) + +// So when using intervals of those basic structures it is not necessary to +// sum up to large numbers, which is what Sieve methods with suffix '_i' and +// corresponding Psieve patterns internally do, as they are not checking for periodicity. +// Instead we can calculate the list of intervals beforehand and use it at will. +// Also 'beforehand' doesn't exclude realtime use: it's easy to write a Function that +// generates Sieves and derives Patterns from it, which, with placeholder patterns, +// can be exchanged on the fly + + +// choose factors and calculate lcm (see 3b), +// as a summation limit it determines one period of intervals + +a = [5, 6, 8]; + +m = a.lcmByGcd; + +// calculate one period of intervals, plot the symmetric structure + +x = Sieve.union_i(5, 6, 8, `m); + +x.plot; + + +// sieve loop without counting high + +Pseq(x.list, 5).asStream.all.plot + + +// second Sieve + +( +b = [20, 17]; +n = b.lcmByGcd; +v = b ++ `n; +y = Sieve.union_i(*v); +y.plot; +) + +// make list for use with arbitrary Patterns + +z = x.list ++ y.list; + +z.plot; + + +// alternating sieves + +Pseq(z, 3).asStream.all.plot; + + +// sequencing random segments of random length +// this is done with Pindex, an ascending index list of random length and a random offset + +// Function for Plazy + +q = { Pindex(z, Pseq((0..rrand(10, 20))) + z.size.rand) } + +Pn(Plazy(q), 30).asStream.all.plot; + + +// sequencing randomly repeated random segments of random length + +q = { Pindex(z, Pseq(((0..rrand(10, 20)) ! rrand(1, 5)).flat) + z.size.rand) } + +Pn(Plazy(q), 20).asStream.all.plot; +:: + + + +SECTION::3) Periodicity of intervals with elementary operations + +subsection::3a) Periodicity of intervals with elementary operations + +code:: +// For 'union' and no offsets one period of intervals is given with summation limit +// equal to the least common multiple (lcm) of the generating numbers. +// (if one number divides another, the larger one can be dropped) + +// The period length (number of intervals per period) is thus lesser than the lcm. +// A symmetric structure is produced, for 'union' the period is equal to its mirror, +// in other words the produced sequence is a concatenation of symmetric segments + +// With 3, 7 and 8 lcm equals 168 + +a = Sieve.union_i(3, 7, 8, `168) + +a.plot + +// number of intervals per period + +a.size + +// For symmetric difference and difference lcm also plays a role, +// but it's a bit different. +// As (offset 0) 0 is not included, the interval sequence doesn't really start from there, +// so with limit = lcm the period is incomplete (although the segment is already symmetric) + +Sieve.symdif_i(3, 7, 8, `168).plot + + +// To get the full picture take twice lcm as limit: +// the interval in the middle was not included before ! + +Sieve.symdif_i(3, 7, 8, `(168 * 2)).plot + + + +// you can get the continuation to symmetry (begin = end) +// with a real start point as offset: + +Sieve.symdif_oi(3, -3, 7, 0, 8, 0, `(168 + 3)).plot; + +Sieve.dif_oi(3, -3, 7, 0, 8, 0, `(168 + 3)).plot; +Sieve.dif_oi(7, -7, 3, 0, 8, 0, `(168 + 7)).plot; +Sieve.dif_oi(8, -8, 3, 0, 7, 0, `(168 + 8)).plot; + + +// In other words in the latter cases the produced sequence is a +// concatenation of symmetric segments, in which begin/end points are merged. +:: + + +subsection::3b) Types of symmetry +anchor::3b:: + +Symmetric structures in periodic series occur as different types, depending if the period length is even or odd. + +DEFINITION: + +numberedList:: +##Lets's call a period 'symmetric' iff it's equaling its reverse. +##Lets's call a period 'quasi-symmetric' iff the continuation with its first element is symmetric. +##If a sequence contains a symmetric or quasisymmetric period, there exists a symmetric or quasisymmetric period starting in its middle (or just right from it when odd), +let denote it its 'coperiod'. +:: + + +STATEMENTS (formal proof omitted, but rather straightforward): + +numberedList:: +##If the period length is even, a symmetric period corresponds to a symmetric coperiod and a quasisymmteric period corresponds to a quasisymmteric coperiod. +##If the period length is odd, a symmetric period corresponds to a quasisymmteric coperiod. +##Only a period of identic elements can be symmetric and quasi-symmetric at the same time. +:: + +subsection::3c) Analysis tools +anchor::3c:: +code:: +// Method 'checkSymmetricPeriods' applies to Arrays resp. intervals of Sieves +// and checks for periods and possible symmetries. +// It returns an array with 4 items: +// (1) the sequence clumped in (quasi-)symmetric (or asymmetric) chunks +// (2) the index offset of the first (quasi-)symmetric period +// (3) a symbol indicating if the period length is even or odd +// (4) an array of Booleans indicating the completeness of the clumped chunks (incomplete periods can be of any type) + +// Some important points here: +// (1) 'checkSymmetricPeriods' searches for smallest periods and its (possible) symmetry +// (2) 'checkSymmetricPeriods' is supposing that no prefix items are introducing +// a periodicity, thus a sequence like 7, 8, 9, 1, 2, 3, 2, 1, 2, 3, 2, 1 ... +// will be regarded as non-periodic (this e.g. happens when offsets are far apart!). +// (3) In the case of odd quasi-symmetric periods the symmetric coperiod is searched for +// and preferred (if it's in the range) +// (4) To get meaningful results for sieves and its elementary operations – +// due to (1) and (3) – it is recommended to check sufficiently large sieves, +// e.g. set the limit to three times the lcm of the generators. + +// make a Sieve with generating prime Integers 3, 7, 8 +// regard a section of three time the expected period length + +( +a = Sieve.symdif_i(3, 7, 10, `(210 * 3)); +a.plot; +) + +// store analysis data +b = a.checkSymmetricPeriods + +// clumped sequence (long) +b[0] + +// symmetry types of chunks and completions, the first relevant period is at position 1 and quasisymmetric +b[1..2] + +// 'checkCharacteristicPeriod' returns an array with first characteristic period, +// index offset, length type (even or odd) and symmetry type + +a.checkCharacteristicPeriod + +// you can plot it directly, compare with the sieve plot, where period starts at index 41 + +a.plotCharacteristicPeriod +:: + + +subsection::3d) Symmetry types of elementary operations without offset + +code:: +// Some observations of types occuring, no proof. +// Connections between types and used numbers are not obvious here: +// all symmetry types of an operator occur with tuples of coprime and not-coprime numbers + +// union: + +// symmetric odd period +( +a = Sieve.union_i(3, 7, `42); +a.plot; +a.plotCharacteristicPeriod; +) + +// symmetric even period +( +a = Sieve.union_i(4, 9, `72); +a.plot; +a.plotCharacteristicPeriod; +) + + +// symdif: + +// symmetric odd period +( +a = Sieve.symdif_i(8, 9, `216); +a.plot; +a.plotCharacteristicPeriod; +) + +// quasi-symmetric even period +( +a = Sieve.symdif_i(7, 9, `189); +a.plot; +a.plotCharacteristicPeriod; +) + +// dif: + +// symmetric odd period +( +a = Sieve.dif_i(5, 6, `90); +a.plot; +a.plotCharacteristicPeriod; +) + + +// quasi-symmetric even period +( +a = Sieve.dif_i(6, 10, `90); +a.plot; +a.plotCharacteristicPeriod; +) +:: + + +subsection::3e) Symmetry types of elementary operations with offset + +code:: +// If generators are coprime all is quite straight: offsets will not change the +// sum of the period equal to the least common multiple but will only cause a shift. +// This was elaborated by Xenakis in [1] + + +// Things become more complicated when generators have prime factors in common: +// still period sums are preserved, but symmetry types can change; +// asymmetric periods occur. One and the same tuple of generators can cause +// different combinations of period types with different offsets. + + +// Here's a little helper Function to analyze characteristics of different offsets +// for a given choice of generating integers + +( +f = { |operator = \union_i ...generators| + var sieve, types, allGens, lcm, data, input, offsets; + //collect all offset combinations + offsets = (generators.collect { |i| (0..i-1) }).allTuples; + + offsets.collect { |offset| + lcm = lcmByGcd(*generators); + input = [operator] ++ [generators, offset].flop.flat ++ Ref(lcm * 4); + sieve = Sieve.perform(*input); + data = sieve.checkCharacteristicPeriod; + ([operator, offset] ++ (data.drop(1)) ++ + ["lcm " ++ lcm.asInteger] ++ ["periodSum " ++ data.first.sum]).postln; + }; + "" +} +) + +// this pair of generators gives three different types: odd asym, odd sym, even sym +f.(\union_oi, 8, 12) + +// check: +// odd asymmetric +Sieve.union_oi(8, 0, 12, 1, `48).plot; + +// odd symmetric +Sieve.union_oi(8, 0, 12, 2, `48).plot; + +// even symmetric +Sieve.union_oi(8, 0, 12, 4, `48).plot; + + +// odd sym, even sym, even asym +f.(\union_oi, 12, 20) + +// odd asym, even sym +f.(\union_oi, 15, 20) + +// odd sym, even asym +f.(\union_oi, 9, 15) + + +// More types result from more fixed generators with varying offsets +// here: odd sym, odd asym, even sym, even asym + +f.(\union_oi, 8, 10, 12) + + + +// Also note that trivial genrator combinations for union without offset (when dividing each other), +// bring different results with offsets + +// sequence of equal intervals (2) + +Sieve.union_i(2, 6, 12, `48) + + +// asymmetric periods with same generators and offsets + +Sieve.union_oi(2, 0, 6, 5, 12, 1, `48).plot; + +// Under same assumption of generators with prime factors in common, a +// similar enrichment of symmetry types occurs with operators 'dif' and 'symdif' +// when offsets are used. In contrast to 'union' but as with 'dif' and 'symdif' +// without offsets, quasisymmteric periods occur. + + +// changing of symmetry types can also be done by looped sequencing of logical operations + +// symmetric period produced by operator 'union' + +a = PSVop_i([6, 5, 7], \u).iter.nextN(500).toSieve(\i, \i); + +a.plotCharacteristicPeriod; + + +// altered, here still symmetric with logical sequence + +a = PSVop_i([6, 5, 7], Pseq([\u, \d, \sd, \d], inf)).iter.nextN(500).toSieve(\i, \i); + +a.plotCharacteristicPeriod; +:: + + +SECTION::4) Troubleshooting + +subsection::4a) Critical inputs, limits + +code:: +// Due to the definition of sieves there are input combinations which +// might result in massive looping without any result. + +// Default settings are chosen in a way that this shouldn't result in hangs immediately, +// nevertheless it's the users's responsibility to choose meaningful input values. + + +// E.g. here we demand multiples of 3 which, at the same time, shouldn't be multiples of 3 ... +// The result nil is given not before the limit of 65536 is reached by summation, +// benchmarking indicates that. + +PSVdif([3, 3], 10).asStream.next + +{ PSVdif([3, 3], 10).asStream.next }.bench + +Sieve.dif(3, 3) + +{ Sieve.dif(3, 3) }.bench + + + +// similar here, no intersection + +PSVsect_o([3, 0, 3, 1], 10).asStream.next + +{ PSVsect_o([3, 0, 3, 1], 10).asStream.next }.bench + +Sieve.sect_o(3, 3) + +{ Sieve.sect_o(3, 3) }.bench + + +// Another critical operation is intersection with larger coprime numbers + +nthPrime(70) +-> 353 + +nthPrime(71) +-> 359 + + +a = PSVsect([353, 359]).asStream; + +// first intersection at 0, but no further one (below global limit 65536) + +a.nextN(2) + + +// you can set the limit, but it's a rather inefficient way to +// generate just a series of equal intervals ... + +a = PSVsect([353, 359], limit: 2 ** 30).asStream; + +a.nextN(20) + +{ a.nextN(20) }.bench + + +// The largest Integer with 32 bit is 2 ** 31 - 1. +// You can set 'limit' with Sieves and Psieve patterns (for instances and globally) +// up to 2 ** 31 - 1 - maxGeneratingInteger. +// This ensures that the threshold check doesn't exceed the Integer range. + + +// So if you're sure about useful inputs +// you can set a high global limit for calculus with large numbers and/or long streams + +Psieve.limit = 2 ** 31 - 536892 + +{ a = PSVunion([253630, 536891]).asStream.nextN(10000) }.bench + + +// reset global limit + +Psieve.limit = 65536 + + +// Note that Psieve is a bit more flexible as Sieve in this regard +// it allows to set summation limit and maxLength. + +Sieve.limit = 2 ** 31 - 536892 + +{ a = Sieve.union(253630, 536891) }.bench + +a.list.size + + +// reset global limit + +Sieve.limit = 65536 +:: + + +subsection::4b) Calculating least common multiples +anchor::4b:: +code:: +// For calculating period lengths the related operations of greatest common divisor +// and least common multiple are relevant (e.g. see [1]) + +// Up to SC 3.7.2 built-in method 'lcm' fails for large Integers, +// though this has been fixed in 3.8: + +lcm(248214, 1027542) + +-> 6696095 + + +// A prime factor analysis shows: + + +a = [248214, 1027542].collect(_.factors) + +-> [ [ 2, 3, 41, 1009 ], [ 2, 3, 41, 4177 ] ] + + +// Thus the result has to be + +2.0 * 3 * 41 * 1009 * 4177 + +-> 1036789878 + + +// Why is 2.0 needed above ? +// The result of an Integer multiplication is an Integer, +// thus crossing the int32 limit is silent and can easily be overlooked + +3768562 * 876876 + +-> 1731721688 + + +3768562.0 * 876876 + +-> 3304561572312 + + +// The methods lcmByFactors and lcmByGcd contain the relevant threshold checkes, +// they are much slower than 'lcm' but reliable also with large Integers. +// 'lcmByFactors' returns an array with lcm as first item, an array with prime factors +// of lcm as second item and an array of receiver's and all arguments' prime factors. +// Alternatively the least common multiple can be calculated +// via the greatest common divisor, this is done by method 'lcmByGcd' + +lcmByFactors(248214, 1027542) +lcmByGcd(248214, 1027542) + + +// if calculation exceeds the int32 limit a warning is given, the result is a float + +lcmByFactors(135630546, 429496729) +lcmByGcd(135630546, 429496729) + + +// also more args can be passed (all are integers < 2 * 31), +// as lcmByGcd uses gcd internally, this might fail with more than 2 +// large numbers, whereas lcmByFactors still finds the result + +lcmByGcd(135630546, 429496729, 610337457) +lcmByFactors(135630546, 429496729, 610337457) + +:: + +anchor::5:: +SECTION::5) Audio examples + +code:: + +// synthdefs to play with +( +SynthDef(\noise_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, rq = 0.1, amp = 0.1| + var sig = { WhiteNoise.ar } ! 2; + sig = BPF.ar(sig, freq, rq) * + EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2) * + (rq ** -1) * (250 / (freq ** 0.8)); + OffsetOut.ar(out, sig); +}).add; + +SynthDef(\sin_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { SinOsc.ar(freq, Rand(0, 2pi)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; + + +SynthDef(\saw_grain, { |out = 0, freq = 400, att = 0.005, rel = 0.1, amp = 0.1| + var sig = { VarSaw.ar(freq, Rand(0, 1)) } ! 2; + sig = sig * EnvGen.ar(Env.perc(att, rel, amp), doneAction: 2); + OffsetOut.ar(out, sig); +}).add; +) +:: + + +subsection::5a) Applying sieve intervals to (micro) rhythms + +code:: +( +// rhythm by sieve intervals + +~delta = 0.05; +~rhy = PSVunion_i([4, 6, 7]); + +p = Pbind( + \instrument, \noise_grain, + \dur, PL(\rhy) * PL(\delta), + \att, 0.01, + \rel, 0.05, + \amp, 0.1, + \midinote, Pwhite(50, 90), + \rq, 0.1 +).play +) + + +// change to micro rhythms + +( +~delta = 0.01; +~rhy = PSVsymdif_i([4, 6]); +) + +// test with different data + +~rhy = PSVsymdif_i([4, 6, 9]) + +~rhy = PSVsymdif_i([6, 9, 2]) + +~rhy = PSVsymdif_i([9, 2]) + +~rhy = PSVsymdif_i([3, 4]) + +~rhy = PSVsymdif_i([3, 4, 7]) + + +p.stop +:: + + +anchor::5b:: +subsection::5b) Sequentially generating new sieve patterns for rhythm and pitch + +code:: +( +// rhythm by sieve intervals + +~delta = 0.1; +~rhy = PSVunion_i([4, 6, 7]); + +// some more params for live change + +~rel = 0.05; +~midi = Pwhite(50, 90); +~rq = 0.1; + +q = Pbind( + \instrument, Prand([\noise_grain, \sin_grain], inf), + \dur, PL(\rhy) * PL(\delta), + \att, 0.005, + \rel, PL(\rel), + \amp, 0.1, + \midinote, PL(\midi), + \rq, PL(\rq) +).play +) + + +// turn to micro rhythm +( +~delta = 0.01; + +// instead of Pn + Plazy also Pspawner with method .seq could be used +~rhy = Pn(Plazy { + var r = { rrand(2, 30) } ! 2; + "rhythm generators: ".post; r.sort.postln; + PSVsymdif_i(r, rrand(20, 30)) +}); + +// numbers generated by PSVsymdif_i are used above and below a central pitch +~midi = Pn(Plazy { + var r = { rrand(2, 10) } ! 2; + "pitch generators: ".post; r.sort.postln; + PSVsymdif_i(r, rrand(10, 20)) * PLseq([1, -1]) + rrand(50, 95) +}); + + +// sequencing rq and release time +~rq = Pstutter(Pwhite(2, 5), PLseq([0.005, 0.01, 0.1])); + +~rel = Pstutter(Pwhite(2, 5), Pn(Pshuf([0.05, 0.1, 0.2]))); +) + +q.stop; +:: + + + +anchor::5c:: +subsection::5c) Sequencing instrumental variation with sieves + +code:: +( +~delta = 0.15; +~rhy = 1; +~rel = 0.04; +~midi = 70; +~instrument = \sin_grain; +~rq = 0.01; +~amp = 0.1; +~type = \note; + +r = Pbind( + \instrument, PL(\instrument), + \dur, PL(\rhy) * PL(\delta), + \att, 0.015 * Pwhite(0.8, 1.2), + \rel, PL(\rel), + \amp, PL(\amp), + \midinote, PL(\midi), + \rq, PL(\rq), + \type, PL(\type) +).play +) + +// define variation with sieve +( +~instrument = Pstutter( + PSVunion_i([5, 7, 13]), + PLseq([\saw_grain, \noise_grain, \sin_grain, \noise_grain]) +) +) + +// pitch sequence based on sieve +( +~midi = Pstutter(Pwhite(2, 5), PSVunion_i([10, 8, 17])) * PLseq([1, -1]) + 80; +~rel = 0.45; +~amp = 0.06; +) + +// transpositions +( +~midi = Pstutter(Pwhite(2, 5), PSVunion_i([10, 8, 17])) * PLseq([1, -1]) + + 80 + Pstutter(Pwhite(10, 20), Pwhite(-5, 5)); +) + +// microtonal transpositions and added fifths +( +~midi = Pstutter(Pwhite(2, 5), PSVunion_i([10, 8, 17])) * PLseq([1, -1]) + 80 + + Pstutter(Pwhite(10, 20), Pwhite(-10.0, 5)) + + Prand([0, [0, 7]], inf); +) + +// interfering curves generated by 'union' +( +~midi = [55, 62] + PSVunion_oi([55, 0, 57, 1, 58, 2, 59, 3]); + +~rel = Pstutter(Pwhite(2, 5), Pn(Pshuf([0.05, 0.05, 0.1, 0.5]))); +) + +r.stop +:: + + diff --git a/HelpSource/Tutorials/Smooth_Clipping_and_Folding.schelp b/HelpSource/Tutorials/Smooth_Clipping_and_Folding.schelp new file mode 100644 index 0000000..a8d38a2 --- /dev/null +++ b/HelpSource/Tutorials/Smooth_Clipping_and_Folding.schelp @@ -0,0 +1,207 @@ +TITLE::Smooth Clipping and Folding +summary::a suite of pseudo ugens for smooth clipping and folding +categories::Libraries>miSCellaneous>WaveFolding +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/SmoothClipS, Classes/SmoothClipQ, Classes/SmoothFoldS, Classes/SmoothFoldQ, Classes/SmoothFoldS2, Classes/SmoothFoldQ2 + +DESCRIPTION:: + +Wave folding is a synthesis technique from analog days, going back to Donald Buchla and the tradition of west coast synthesis. Smooth clipping and folding pseudo ugens from miSCellaneous lib come in variants which include quadratic and sinusoidal waveshaping and allow clipping and folding without aliasing. This can also be used for buffer scratching, a synthesis technique which I have been experimenting with recently with great fun. + + +EXAMPLES:: + +anchor::Ex. 1:: +subsection::Ex. 1: Different types of folding + +code:: + +// A typical usage is preamplifying a signal, here we start with a sine wave, compare plots + +{ + [ + // just smooth clipping + SmoothClipS.ar(SinOsc.ar(50) * 10), + + // folding with main lib's Fold ugen + Fold.ar(SinOsc.ar(50) * 10, -1, 1), + + // folding with rather low smoothing + // wave shaper is partiallly a sine wave + SmoothFoldS.ar(SinOsc.ar(50) * 10, smoothAmount: 0.3), + + // folding with maximum smoothing + // wave shaper is full sine wave + SmoothFoldS.ar(SinOsc.ar(50) * 10, smoothAmount: 1), + + // wave is folded back only to border ranges + SmoothFoldS.ar(SinOsc.ar(50) * 10, foldRange: 0.3), + + // folding with different sizes of border ranges + SmoothFoldS2.ar(SinOsc.ar(50) * 10, foldRangeLo: 0.5, foldRangeHi: 0.2) + ] +}.plot(1/50) + +:: + +image::attachments/Smooth_Clipping_and_Folding/fold_examples.png:: + + + +anchor::Ex. 2:: +subsection::Ex. 2: Generating rich spectra by folding sine waves + +code:: + +// Folding ugens do multichannel expansion, let two anticyclic sines control the fold range, +// control smoothing amount with MouseX + +( +x = { + var source = SinOsc.ar(50); + SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1), MouseX.kr(0, 1)) +}.scope +) + +x.release + + +// Compare with the parabolic smoothing variant, the difference isn't great in this case + +( +x = { + var source = SinOsc.ar(50); + SmoothFoldQ.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1), MouseX.kr(0, 1)) +}.scope +) + +x.release + + +// slow modulations of source frequency with independent LFOs + +( +x = { + var source = SinOsc.ar(50 * { LFDNoise3.kr(0.1).range(0.98, 1.02) } ! 2); + SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1)) +}.scope +) + +x.release + + +// Adding more complexity by applying preamplification (causes more folding) and adding an offset, +// these operations are also L/R-independent + +( +x = { + var source = SinOsc.ar( + 50 * { LFDNoise3.kr(0.1).range(0.98, 1.02) } ! 2, + 0, + { LFDNoise3.kr(0.15).range(0.5, 3) } ! 2, + { LFDNoise3.kr(0.2).range(-2, 2) } ! 2 + ); + SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.kr(0.05, [0, pi]).range(0.1, 1)) +}.scope +) + +x.release +:: + + + +anchor::Ex. 3:: +subsection::Ex. 3: Applying modulated folding to LFO sources + +code:: + +// the other way round, take a lfo source and modulate folding parameters, here the relative folding range + +( +x = { + var source = LFDNoise3.ar(0.3!2).range(0.5, 1); + SmoothFoldS.ar(source, -0.1, 0.1, SinOsc.ar([50, 50.1]).range(0.1, 1) ) +}.scope +) + +x.release + + +// modulating fold bounds + +( +x = { + var source = LFDNoise3.ar(0.3!2).range(0.5, 1); + var bounds = SinOsc.ar([50, 50.1]).range(0.02, 0.1); + SmoothFoldS.ar(source, bounds.neg, bounds) +}.scope +) + +x.release + + +// modulating bounds and range + +( +x = { + var source = LFDNoise3.ar(0.3!2).range(0.5, 1); + var range = SinOsc.ar([50, 50.1]).range(0.02, 0.1); + SmoothFoldS.ar(source, range.neg, range, SinOsc.ar([200, 200.1]).range(0.5, 1)) +}.scope +) + +x.release +:: + + + +anchor::Ex. 4:: +subsection::Ex. 4: Buffer scratching with folded signal as position control + +code:: + +// Interesting micro textures can be generated that way. +// Technically this is waveshaping with an audio buffer as transfer function and the folded signal as source. + +// compare with granulation, sound file from buffer granulation tutorial + +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); +// This searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or a removed sound file, pass the concerned path. + + +( +SynthDef(\bufScratchFold, { |bufnum = 0, globalFreq = 0.7, localOscSize = 0.01, foldRange = 0.28, + localFreq = 0.87, preAmp = 1.4, smoothAmount = 0.36| + var sig = BufRd.ar( + 1, + bufnum, + ( + // define global and local movement + LFDNoise3.ar(globalFreq).range(0.2, 0.7) + + SmoothFoldS.ar( + // adding space by decorrelating the local scratching / oscillation + LFTri.ar(localFreq * ({ LFDNoise3.ar(0.2).range(0.999, 1.001) } ! 2)) * preAmp, + foldRange: foldRange, + smoothAmount: smoothAmount + ) * localOscSize + ) * BufFrames.ir(bufnum) + ); + // as local oscillation can stick with positive or negative values, a dc leaker is recommended + Out.ar(0, LeakDC.ar(sig) * EnvGate.new) +}).add +) + +x = Synth(\bufScratchFold, [bufnum: b]) + +x.set(\preAmp, 5.4) +x.set(\foldRange, 0.08) +x.set(\localFreq, 0.5) +x.set(\localOscSize, 0.05) +x.set(\foldRange, 0.02) +x.set(\localFreq, 0.1) + +x.release + +:: + + diff --git a/HelpSource/Tutorials/VarGui_shortcut_builds.schelp b/HelpSource/Tutorials/VarGui_shortcut_builds.schelp new file mode 100644 index 0000000..f73be71 --- /dev/null +++ b/HelpSource/Tutorials/VarGui_shortcut_builds.schelp @@ -0,0 +1,907 @@ + + +TITLE::VarGui shortcut builds +summary::quick building of slider / player guis for synths and sequencing +categories:: Libraries>miSCellaneous>GUI +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/VarGui, Tutorials/HS_with_VarGui, Tutorials/PLx_suite, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation + +DESCRIPTION:: + +VarGui allows combined control of Synths, Pbinds / EventStreamPlayers and Tasks in one GUI. Many of its options though may not be relevant for most usages, also control specs were to be given directly (changed with v0.5). Shortcut build methods take advantage of SynthDef controlspec metadata, if defined (or global ControlSpecs), and autogenerate Pbinds for sequencing. Controls and Pbinds can be customized with options. +Main tools are the methods strong::sVarGui:: ( strong::s::ynth ), strong::pVarGui:: ( strong::p::attern ) and compound builders strong::spVarGui:: / strong::psVarGui::. Methods strong::sVarGui:: / strong::pVarGui::, applied to a single Symbol / String, produce a VarGui for one or more Synth(s) or Pbind(s) based on the referred single SynthDef ( link::#Ex.1a::, link::#Ex.1b::, link::#Ex.2a::, link::#Ex.2b:: ). Both methods also apply to collections of SynthDef Symbols / Strings ( link::#Ex.3a::, link::#Ex.3b:: ), whereas strong::spVarGui:: and strong::psVarGui::, builders of mixed Synth / Pbind VarGuis, expect collections of two items which may be Symbols / Strings or collections of Symbols / Strings ( link::#Ex.3c:: ). +Examples are using Patterns from dynamic scope link::Tutorials/PLx_suite:: for conveniently refering to environmental variables. + + +SECTION::1. Synth GUIs + +anchor::Ex.1a:: +subsection::Ex.1a: default instrument + +code:: + +( +s = Server.local; +Server.default = s; +s.boot; +) + + +// No metadata is defined with default instrument, per default global ControlSpecs are used. +// Here its definition from Event.sc: + +( +SynthDef(\default, { arg out=0, freq=440, amp=0.1, pan=0, gate=1; + var z; + z = LPF.ar( + Mix.new(VarSaw.ar(freq + [0, Rand(-0.4,0.0), Rand(0.0,0.4)], 0, 0.3)), + XLine.kr(Rand(4000,5000), Rand(2500,3200), 1) + ) * Linen.kr(gate, 0.01, 0.7, 0.3, 2); + OffsetOut.ar(out, Pan2.ar(z, pan, amp)); +}, [\ir]).storeOnce; +) + + +// With the next line you should get a VarGui with controls for freq, amp and pan. +// If not, global ControlSpecs and / or the default instrument have probably been changed, +// see below how to display and change global Specs. +// In global ControlSpecs amp defaults to 0, you have to raise in order +// to hear sound after pressing the player button + +\default.sVarGui.gui; + + +// automatic use of global ControlSpecs turned off, Synths with default args + +\default.sVarGui(useGlobalSpecs: false).gui; + + +// global specs, not all of them ControlSpecs, are stored in Spec.specs ... + +Spec.specs.associationsDo(_.postln); + + +// ... they can be added or replaced with .add +// for default instrument examples +// we replace \amp spec with a new ControlSpec with default 0.1 + +Spec.add(\amp, [0, 1, \lin, 0, 0.1]); + + +// generating a number of Synths, controls can be excluded, +// parallel slider dragging with Alt, parallel button action with Shift-click + +\default.sVarGui(exclude: \pan, num: 3).gui; + + + +// controls can be replaced ... + +\default.sVarGui(ctrReplace: [\freq, [400, 440, \exp, 0, 420]]).gui; + + +// ... and added, before or after the main block of controls from metadata or global ControlSpecs, +// this collection is empty here, so ctrBefore and ctrAfter are equivalent + +\default.sVarGui(useGlobalSpecs: false, ctrBefore: [\freq, [400, 440, \exp, 0, 420]]).gui; + + +// bad definition, \freq is already used as global ControlSpec + +\default.sVarGui(ctrBefore: [\freq, [300, 1000, \exp, 0, 440]]).gui; // WRONG + + +:: + +anchor::Ex.1b:: +subsection::Ex.1b: SynthDefs including metadata + + +SynthDef with defined controlspec metadata. The specs can be stored as ControlSpecs or Arrays, may also be Symbols / Strings refering to the global dictionary of Specs (Spec.specs). It's only convention to store specs under the key \specs, it can be anything else, and nothing prevents you from storing more than one dictionary of ControlSpecs per SynthDef - the VarGui shortcut methods have a metaKey arg (default: \specs) which determines where to lookup in the metadata dictionary. + + +code:: + +( +SynthDef(\buzz, { arg freq = 400, out, gate = 1, freqDev = 0.01, att = 0.01, dec = 0.01, susLevel = 0.5, rel = 1, + cutoff = #[1000, 1000, 1000], rq = 0.25, amp = 0.2, preAmp = 1, maxDelay = 0.03; + var src, srcFreq, sig; + sig = Mix.fill(3, { |i| + // chorus spread over three registers + srcFreq = (2 ** i) * freq * (1 + Rand(freqDev.neg, freqDev)) / 2; + src = RLPF.ar(Saw.ar(srcFreq, preAmp), cutoff[i], rq).softclip * amp * + EnvGen.kr(Env.adsr(att, dec, susLevel, rel), gate, doneAction: 2); + // random spatialization (for sequencing) by L/R delay + [DelayL.ar(src, maxDelay, Rand(0, maxDelay)), DelayL.ar(src, maxDelay, Rand(0, maxDelay))] + }) ; + // ensure sample accurate output for events of short durations + OffsetOut.ar(out, sig); + + }, metadata: ( + specs: ( + freq: [20, 5000, \exp, 0, 80], + gate: [0, 1.0, \lin, 0, 1], + freqDev: [0.0, 0.02, \lin, 0, 0.002], + att: [0.01, 0.2, \lin, 0, 0.01], + dec: [0.01, 0.2, \lin, 0, 0.01], + susLevel: [0.01, 1, \lin, 0, 0.5], + rel: [0.01, 2, \exp, 0, 1], + cutoff: [200, 5000, \exp, 0, 1000], + rq: [0.1, 0.9,\lin, 0, 0.2], + amp: [0.0, 1, \lin, 0, 0.2], + preAmp: [0.9, 5, \lin, 0, 1], + maxDelay: [0, 0.01, \lin, 0, 0.002] + ), + // doesn't matter for VarGui if spec defined as Array or ControlSpec, + // an arbitrary number of arbitrarily named alternative Spec Events may be passed, + // for non-sequencing use adsr params may be dropped + basicSpecs: ( + freq: [20, 5000, \exp, 0, 80], + gate: [0, 1.0, \lin, 0, 1], + cutoff: [200, 5000, \exp, 0, 1000], + rq: [0.1, 0.9,\lin, 0, 0.2], + amp: [0.0, 1, \lin, 0, 0.2], + preAmp: [0.9, 5, \lin, 0, 1] + ) + ) +).add; +) + + +// here metadata includes a gate spec with default 1 +// metadata has priority over global ControlSpecs +// metaKey \specs used per default + +\buzz.sVarGui.gui; + + +// use gui options for better arrangement + +\buzz.sVarGui(num: 4).gui(tryColumnNum: 2, sliderHeight: 16); + + +// alternative metadata, metaKey to be passed, +// mostly sounds different from last version +// because of fixed max chorus-width param freqDev + +\buzz.sVarGui(num: 4, metaKey: \basicSpecs).gui(tryColumnNum: 2); + +:: + + + +SECTION::2. Sequencing GUIs + +Controlling Pbinds / EventStreamPlayers with VarGui is based on (a) the setting of environmental variables and (b) the proper definition of Pbinds with Patterns of link::Tutorials/PLx_suite:: or Patterns with functional code ( link::Tutorials/Event_patterns_and_Functions:: ) so that EventStreamPlayers get the updated variable values in the following events. + +Basic example of a Pbind to get envir values: + +code:: +p = Pbind( + \dur, Pfunc { ~dur } * Pseq([2,1,1], inf), + \legato, Pfunc { ~legato }, + \amp, Pfunc { ~amp } +) + +// or + +p = Pbind( + \dur, PL(\dur) * Pseq([2,1,1], inf), + \legato, PL(\legato), + \amp, PL(\amp) +) + +:: + +Especially when based on a SynthDef with a large number of args writing a Pbind can be lengthy, moreover redundant if there are many pbind pairs of the form + +code:: + +[ aSymbol, Pfunc { ~aSymbol } ] + +:: + +The pVarGui method is going the opposite way: Pbind pairs get this most simple form for all args with metadata or global ControlSpecs defined, though it's possible to exclude keys and add respectively replace customized pairs before and after the automatically generated ones. All you need is a SynthDef that is suited for Pbind sequencing (known to SynthDescLib by being strong::add::ed, properly defined Envelopes). +warning:: As a lot of the underlying Pbind structure (by default all of it !) is hidden, it's possible to call pVarGui without knowing anything about Patterns. Nevertheless it's highly recommended to be aware of the mechanisms of Pbind for applying useful sequencing customizations and having a look at the fully written Pbind examples in link::Classes/VarGui::. Clearly: adding, replacing and excluding Pbind pairs without seeing the resulting code is a possible source of error, so if using VarGui this way better start slowly and go on stepwise. With the post option you can print out the ordered list of pairs. +:: + +anchor::Ex.2a:: +subsection::Ex.2a: default instrument + +code:: + +// for default instrument examples +// we replace \amp spec with a new ControlSpec with default 0.1 + +Spec.add(\amp, [0, 1, \lin, 0, 0.1]); + + +// Most simple example to get a VarGui controlling a Pbind / EventStreamPlayer with +// default instrument, control of duration and legato is automatically added. +// As with the sVarGui method synth controls are added when found in metadata definition +// or global ControlSpecs, different from sVarGui \gate is excluded by default. + +\default.pVarGui.gui; + + +// adding a pattern pair - if it contains one of the keys \note, \midinote or \degree +// the freq pair is removed automatically, see posted Pbind pairs + +\default.pVarGui(pAfter: [\degree, Pwhite(0,5)], post: true).gui; + + +// pattern pair replacement as in basic example above + +\default.pVarGui(pReplace: [\dur, PL(\dur) * Prand([2,1,1], inf)] ).gui; + + +// adding a pattern pair after the main block of pairs, +// same effect as before + +\default.pVarGui(pAfter: [\dur, Pkey(\dur) * Prand([2,1,1], inf)], post: true).gui; + + +// Internally a Pbind of this form had been generated (see post window), +// in each Event the second Stream with key \dur gets the value from the first, +// overrides it in the Event. + +Pbind( + // pBefore pairs (optinally passed to pVarGui) + ... + + // these are always placed before the main block + \instrument, \default, + \dur, Pfunc { ~dur }, + \legato, Pfunc { ~legato }, + + // main block of pairs corresponding to args for which + // spec definition was found (if not excluded or replaced), + // ordered like in SynthDef + + \freq, Pfunc { ~freq }, + \amp, Pfunc { ~amp }, + \pan, Pfunc { ~pan }, + + // pAfter pairs (optinally passed to pVarGui) + \dur, Pkey(\dur) * Prand([2,1,1], inf) +) + + +// Additional arrayed control for simple step sequencing with random init values. +// The PLseq degree pattern defaults to repeats = inf and envir = \current. +// It would take values from the current Environment of streamification. + +// Here playing and setting the variables will +// happen in a new Environment generated by the VarGui. + +( +\default.pVarGui( + ctrBefore: [\a, { [0, 5, \lin, 1, rrand(0,6)] } ! 8 ], + pBefore: [\degree, PLseq(\a) ] +).gui; +) + +// A number of Pbinds and control sets can be generated with the num arg, +// control and pattern customization args take Functions (optionally of indices) +// for expansion. + +// This a potentially powerful feature, also suited for producing a real mess ! +// Especially think of possibly inappropriate ranges ! +// If you are unsure try out evaluating code of the form ... + +{ |i| ... } ! n + +// ... separately before plugging in the shortcut methods. + + +// Here the Function passed to ctrBefore has no index arg, +// it just produces 4 different tuples of +// init values for the step sequencers, + +// the pBefore Function determines 4 different octave registers +// quant arg ensures staying in sync based on the passed rhythmic patterns + +( +\default.pVarGui( + /* ctrBefore: */ { [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ] }, + /* ctrReplace: */ [\dur, [0.2, 0.6, \lin, 0.2, 0.2]], + pBefore: { |i| [\degree, PLseq(\a), \octave, i+4] }, + num: 4, + quant: 0.2, + post: true +).gui(tryColumnNum: 2); +) + +:: + +anchor::Ex.2b:: +subsection::Ex.2b: SynthDefs including metadata + + +Automatic Pbind generation in VarGui shortcut builds is especially saving typing if SynthDefs have a lot of args and controlspec metadata defined. + +code:: + +// most simple, controls are built for all args with metadata defined +// arrayed args are detected and controls are established for a corresponding array +// SynthDef from above + +\buzz.pVarGui.gui; + + +// use the exclude option to exclude from automatically generated controls and Pbind pairs +// you would want to do that for a static value or sequencing not to be gui-controlled + + +// always SynthDef default value 0.01 for attack time + +\buzz.pVarGui(exclude: [\att], post: true).gui; + + +// sequencing without control +// RLP filter rq excluded from gui control and automatic Pbind pair generation, +// though added to Pbind pairs again as passed to pBefore (could also be pAfter), +// here PLseq taken as it defaults to inf + +\buzz.pVarGui(exclude: [\rq], pBefore: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui; + + +// same effect on sound, but we have a useless rq control + +\buzz.pVarGui(pAfter: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui; +\buzz.pVarGui(pReplace: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui; + + +// here the pBefore arg is useless as the Pfunc that takes controlled values +// comes after in execution and will overwrite the value per Event + +\buzz.pVarGui(pBefore: [\rq, PLseq([ 0.05, 0.8, 0.8, 0.8]) ], post: true).gui; + + +// establishing a cutoff freq rhythm for all three layers +// remember that in Pbinds arrayed args must be distinguished from the syntax for generating +// multiple synths per Event, this can be achieved by wrapping in an additional array + +\buzz.pVarGui(pReplace: [\cutoff, Pfunc { [~cutoff] } * PLseq([3,1,1]) ]).gui; + + +// step sequencer for quartertone bassline + +( +\buzz.pVarGui( + ctrAfter: [\a, { var lo = 25, hi = 50; [lo, hi, \lin, 0.5, rrand(lo*2, hi*2) / 2 ] } ! 8 ], + pBefore: [\midinote, PLseq(\a)], + post: true +).gui; +) + + + +// step sequencer with two voices +// by passing functions different control ranges and registers are established +// both lines are in a quartertone scale but shifted by an eigthtone +// lines itself can be shifted by an offset ~add + +// modifier keys can be used to perform parallel slider or button actions +// alt for parallel slider movement and shift for parallel button actions (VarGui) + + +( +\buzz.pVarGui( + ctrReplace: [\dur, [0.1, 0.2, \lin, 0.1, 0.2], \amp, [0.0, 0.5, \lin, 0, 0.3]], + ctrAfter: { |i| var d = 0.25; + [\add, [-12, 12, \lin, 0.5, 0], + \a, { [(i*d), 11.5 + (i*d), \lin, 0.25, rrand(0, 23) / 2 + (i*d)] } ! 8 + ] }, + pBefore: { |i| [ + \note, PLseq(\a) + PL(\add), + \octave, 3 + (i*4) + Pwhite(0,1) + ] }, + quant: 0.2, + post: true, + num: 2 +).gui(tryColumnNum: 2); +) + + +:: + + +anchor::Ex.2c:: +subsection::Ex.2c: Combination of parameter control and pattern exchange (JITLib) + +code:: + +( +\buzz.pVarGui( + ctrReplace: [\freq, [20, 1000, \exp, 0, 80]], + pReplace: [ + \cutoff, Pdefn(\cutoff, Pseq([3, 1, 1, 1, 1], inf)) * Pfunc { [~cutoff] }, + \freq, Pdefn(\freq, Pseq([1, 1, 1.3, 1.2, 1], inf)) * Pfunc { ~freq } + ] +).gui; +) + +// start from gui and eval pattern replacements before playing around with sliders + +Pdefn(\freq, Pseq([1, 1, 1.7, 1.3, 1.2], inf)); + +Pdefn(\cutoff, Pseq([2, 1, 1], inf)); + +Pdefn(\freq, 1); + +Pdefn(\cutoff, Pseq([1, 1, 1.7, 1.3, 1.2], inf)); + +:: + +anchor::Ex.2d:: +subsection::Ex.2d: Combination of parameter control and pattern exchange (PLx) + +code:: + +// above done with PL +// note that PLs are taking envir variables from the current Environment by default, +// this is ok for the variables set by VarGui (freq) in its Environment, +// but for PLs to take values from elsewhere we must give the Environment explicitely. +// Suppose we are in topEnvironment here: + +// As PL defaults to repeats = inf, Pseq can be taken without a repeats arg +// for endless looping + +( +~co = Pseq([3, 1, 1, 1, 1]); +~fr = Pseq([1, 1, 1.3, 1.2, 1]); + +\buzz.pVarGui( + ctrReplace: [\freq, [20, 1000, \exp, 0, 80]], + pReplace: [ + \cutoff, PL(\co, envir: \top) * Pfunc { [~cutoff] }, + \freq, PL(\fr, envir: \top) * PL(\freq) + ] +).gui; +) + +// start from gui and eval pattern replacements before playing around with sliders + +~fr = Pseq([1, 1, 1.7, 1.3, 1.2]); + +~co = Pseq([2, 1, 1]); + +~fr = 1; + +~co = Pseq([1, 2, 1.7, 1.3, 1.2]); + + +////////////////////////////////// + + +// alternative version with a PLseq placeholder + +( +~co = [3, 1, 1, 1, 1]; +~fr = [1, 1, 1.3, 1.2, 1]; + +\buzz.pVarGui( + ctrReplace: [\freq, [20, 1000, \exp, 0, 80]], + pReplace: [ + \cutoff, PLseq(\co, envir: \top) * Pfunc { [~cutoff] }, + \freq, PLseq(\fr, envir: \top) * PL(\freq) + ] +).gui; +) + +// start from gui and eval pattern replacements before playing around with sliders + +~fr = [1, 1, 1.7, 1.3, 1.2]; + +~co = [2, 1, 1]; + +~fr = [1]; + +~co = [1, 2, 1.7, 1.3, 1.2]; + +:: + + +SECTION::3. Mixed GUIs + +To control Synths or Pbinds / EventStreamPlayers derived from more than one SynthDef sVarGui and pVarGui can be applied to collections. + +anchor::Ex.3a:: +subsection::Ex.3a: Synths from different SynthDefs + +code:: + +// for default instrument examples +// we replace \amp spec with a new ControlSpec with default 0.1 + +Spec.add(\amp, [0, 1, \lin, 0, 0.1]); + + +// different synths + +[\buzz, \default].sVarGui.gui + + +// in basic form this works equivalently ... + +VarGui(synth: [\buzz, \default]).gui; + + +// ... but for customization the shortcut method sVarGui is more convenient, +// otherwise you'd have to pass or generate controls explicitely (5b). +// sVarGui and pVarGui, applied to SequenceableCollections, expect Dictionaries +// of pairs argName / arg, so you can pass Events. +// Their number must equal the collection's size. + +( +[\buzz, \default].sVarGui( + (ctrReplace: [\freq, [97, 103, \exp, 0, 99]]), + (ctrReplace: [\freq, [194, 206, \exp, 0, 201]]) +).gui; +) + +// more synths + +( +[\default, \buzz].sVarGui( + (ctrReplace: { [\freq, [194, 206, \exp, 0, rrand(194.0, 206)]] }, num: 4), + (ctrReplace: [\freq, [97, 103, \exp, 0, 99]]) +).gui(tryColumnNum: 2, allowSynthBreak: false); +) + +:: + + +anchor::Ex.3b:: +subsection::Ex.3b: Pbinds from different SynthDefs + +code:: + +// overtones, deviations of pitch and pulsation + +( +[\default, \buzz].pVarGui( + (ctrReplace: { |i| var f = (2*i + 1) * 100, d = 0.2, lo = 0.99, hi = 1.01; + [\freq, [f*lo, f*hi, 0, 0, f*rrand(lo,hi)], \dur, [d*lo, d*hi, 0, 0, d*rrand(lo,hi)] ] }, + post: true, + num: 4), + (ctrReplace: [\freq, [97, 103, \exp, 0, 99], \dur, [0.195, 0.205, 0, 0, 0.2] ]) +).gui(tryColumnNum: 2, allowEnvirBreak: false) +) + + +// step sequencer + +( +[\buzz, \default].pVarGui(( + ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ], + ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]], + pBefore: [\degree, PLseq(\a), \octave, 3], + quant: 0.2 + ),( + ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ], + ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]], + pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), + \octave, Pwhite(5,7) ], + quant: 0.2 + ) +).gui(tryColumnNum: 2, allowEnvirBreak: false); +) + +:: + +anchor::Ex.3c:: +subsection::Ex.3c: Synths and Pbinds + + +code:: +// Pbind granulation with \buzz, controls and pbind pairs adapted and added, +// psVarGui (pbind input first) and spVarGui (synth input first) +// apply to collections of two items. + +// If only one type of SynthDef is to be used for Pbind(s) or Synth(s) +// it may be a plain Symbol / String, the corresponding arg tuples may +// be given as plain (not collected) Dictionaries + +// Keep in mind that nevertheless one Dictionary may produce +// more than one Synth (Pbind) + +( +[\buzz, \default].psVarGui( + ( + ctrReplace: [\dur, r = [0.01, 0.05, \lin, 0, 0.03], + \rel, r, + \freq, [100, 1000, \lin, 0, 100], + \amp, [0, 0.5, \lin, 0, 0.15], + \legato, [0.1, 2, \lin, 0, 0.5], + \freqDev, [0, 0.2, \lin, 0, 0.01]], + ctrBefore: [\durDev, [0, 1, \lin, 0, 0.01]], + pAfter: [\dur, Pkey(\dur) * Pfunc { x = 1 + ~durDev; rrand(1/x,x) }], + post: true + ),( + ctrReplace: { [\dur, [0.01, 0.05, \lin, 0, 0.03], + \freq, [100, 1000, \lin, 0, rrand(100, 1000)]] }, + num: 4 + ) +).gui(tryColumnNum: 2, allowEnvirBreak: false); +) + + +// If more than one type of SynthDef is to be used for Pbind(s) or Synth(s) +// Symbols / Strings must be collected, also the corresponding Dictionaries + +// spVarGui just takes input in reversed order (synth first). +// This is independent from representation in the GUI +// which can be determined by args sliderPriority (\var or \synth) +// and playerPriority (\stream or \synth) + +( +[\default, [\buzz, \default]].spVarGui( + ( + ctrReplace: { [\dur, [0.01, 0.05, \lin, 0, 0.03], + \freq, [100, 1000, \lin, 0, rrand(100, 1000)]] }, + num: 4 + ),[ + ( + ctrReplace: [\dur, r = [0.01, 0.05, \lin, 0, 0.03], + \rel, r, + \freq, [100, 1000, \lin, 0, 100], + \amp, [0, 0.5, \lin, 0, 0.15], + \legato, [0.1, 2, \lin, 0, 0.5], + \freqDev, [0, 0.2, \lin, 0, 0.01]], + ctrBefore: [\durDev, [0, 1, \lin, 0, 0.01]], + pAfter: [\dur, Pkey(\dur) * Pfunc { var x = 1 + ~durDev; rrand(1/x,x) }], + post: true + ),( + ctrReplace: [\dur, r = [0.01, 0.05, \lin, 0, 0.03], + \freq, [100, 1000, \lin, 0, 100], + \amp, [0, 0.5, \lin, 0, 0.15], + \legato, [0.1, 2, \lin, 0, 0.5]], + ctrBefore: [\durDev, [0, 1, \lin, 0, 0.01], + \freqDev, [0, 0.2, \lin, 0, 0.01]], + pAfter: [\dur, Pkey(\dur) * Pfunc { var x = 1 + ~durDev; rrand(1/x,x) }, + \freq, Pkey(\freq) * Pfunc { var x = 1 + ~freqDev; rrand(1/x,x) }], + post: true + ) + ] +).gui(tryColumnNum: 2, allowEnvirBreak: false, sliderPriority: \synth, playerPriority: \synth); +) + +:: + +SECTION::4. Differences between shortcut builds and direct VarGui instantiation + + +list:: +## Shortcut methods apply to Symbols / Strings or collections thereof for Synth and Pbind generation and control. Symbols / Strings refer to the corresponding SynthDefs, known to SynthDesLib.global. For passing Synths, nodeIDs, EventStreamPlayers, also Task Functions and Tasks, you would have to call VarGui directly. +## Shortcuts and also direct instantiation (not before v0.5) are using SynthDef metadata and / or global ControlSpecs. Though customization options for specs (exclude, add, replace) are a main feature of the shortcut methods. As a compromise spec- and pbindmaker methods with these options may be plugged into direct instantiation ( link::#5b:: ). +## The pVarGui method invokes automatic Pbind generation with customization options for Pbind pairs (exclude, pBefore, pAfter, pReplace), VarGui expects Pbinds to be passed directly. As a compromise a pbindmaker method with these options may be plugged into direct instantiation ( link::#5b:: ). +## In shortcut methods the strong::num:: arg causes coordinated expansion, all other args (except strong::server::) may optionally be given as Functions of indices. With VarGui input you'd have to pass lengthy nested Arrays or write something like { |i| ... } ! n for every arg explicitely, as sizes of input must match. As a compromise spec- and pbindmaker methods with strong::num:: arg may be plugged into direct instantiation ( link::#5b:: ). +## Reordering / interleaving of controls of different Environments / Synths ( link::Classes/VarGui#Ex. 5a:: and link::Classes/VarGui#Ex. 5b:: ) is not possible with shortcut methods. However this seems to be a quite special feature, with shortcut methods ordering of Synths / Pbinds is primarily defined by order of args, control customization options allow further modifications of order. Finally choosing sliderPriority (\synth or \var first) is a pure gui method option and applies to both ways of VarGui building. +:: + +SECTION::5. Shortcut method specifictions + +Shortcut methods also take Functions, that should return args in a valid form. This can be used for defining controls in different ranges in combination with strong::num::. See examples above. + + +anchor::5a:: +subsection::5a: core shortcut methods + +link::Classes/Symbol#-sVarGui:: + +link::Classes/SequenceableCollection#-sVarGui:: + +link::Classes/Symbol#-pVarGui:: + +link::Classes/SequenceableCollection#-pVarGui:: + + +note:: +The following two methods are equivalent, just take opposite arg order. This is independent of arrangement, which can be determined by gui args sliderPriority (\var or \synth) and playerPriority (\stream or \synth). +:: + +link::Classes/SequenceableCollection#-spVarGui:: + +link::Classes/SequenceableCollection#-psVarGui:: + +anchor::5b:: +subsection::5b: spec- and pbindmaker methods + +In most cases you won't need this, except for reloading customized sequencing VarGuis ( link::#6:: ). For special arrangements methods for making specdata and Pbinds of appropriate Pfuncs can be used for customizing control with direct VarGui instantiation. These methods take args in the same way as sVarGui and pVarGui. + + +link::Classes/Symbol#-sVarGuiSpecs:: + +link::Classes/Symbol#-pVarGuiSpecs:: + +link::Classes/Symbol#-pfuncPbinds:: + +code:: + + +// sVarGuiSpecs returns a list of spec pair lists of the form [\key, specArray, ...] +// derived from SynthDef metadata / global ControlSpecs, +// controls can be excluded, added and replaced + +( +VarGui( + synth: [\default, \buzz], + synthCtr: \default.sVarGuiSpecs ++ + \buzz.sVarGuiSpecs(ctrReplace: [\amp, [0, 0.5, 0, 0, 0.1]]) +).gui; +) + +// shorter + +( +[\default, \buzz].sVarGui( + (), + (ctrReplace: [\amp, [0, 0.5, 0, 0, 0.1]]) +).gui; +) + + +// as with sVarGui arguments can be functions of indices + +( +VarGui( + synth: \default!4 ++ \buzz, + synthCtr: + \default.sVarGuiSpecs(num: 4, + ctrReplace: { |i| var x = i*100 + 400; [\freq, [x, x*1.1, 0, 0, x]] }) ++ + \buzz.sVarGuiSpecs(ctrReplace: [\amp, [0, 0.5, 0, 0, 0.2]]) +).gui(tryColumnNum: 2, allowSynthBreak: false); +) + +// shorter + +( +[\default, \buzz].sVarGui( + (num: 4, ctrReplace: { |i| var x = i*100 + 400; [\freq, [x, x*1.1, 0, 0, x]] }), + (ctrReplace: [\amp, [0, 0.5, 0, 0, 0.2]]) +).gui(tryColumnNum: 2, allowSynthBreak: false); +) + + + +// pVarGuiSpecs also returns a list of spec pair lists, +// just adds specs for dur and legato by default, +// pfuncPbinds returns appropriate Pbinds of Pfuncs +// additional pairs can be added + +// however, compared to pVarGui, more coordination is the user's responsibility: +// specmaker and pbindmaker don't know about each other +// useless control \freq excluded explicitely here + +( +VarGui( + varCtr: + \buzz.pVarGuiSpecs(ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ], + ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]], exclude: \freq) ++ + \default.pVarGuiSpecs(ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ], + ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]], exclude: \freq), + stream: + \buzz.pfuncPbinds(pBefore: [\degree, PLseq(\a), \octave, 3]) ++ + \default.pfuncPbinds(pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), + \octave, Pwhite(5,7)], post: true), + quant: 0.2 +).gui(tryColumnNum: 2, allowEnvirBreak: false); +) + +// shorter + +( +[\buzz, \default].pVarGui(( + ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ], + ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]], + pBefore: [\degree, PLseq(\a), \octave, 3], + quant: 0.2 + ),( + ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ], + ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]], + pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), + \octave, Pwhite(5,7) ], + quant: 0.2 + ) +).gui(tryColumnNum: 2, allowEnvirBreak: false); +) + +:: + + +anchor::6:: +SECTION::6. Save and load + +A VarGui's slider state can be saved via save button and dialog. Loading is straightforward with Synths. You just have to give the correct path and synth arg (which maybe has to be an array). + +code:: + +// change slider positions and save + +\buzz.sVarGui.gui; + +// reload + +VarGui.load("Path_To_XY", "XY", synth: \buzz).gui; + + +// change slider positions and save + +\buzz.sVarGui(num: 4, metaKey: \basicSpecs).gui(tryColumnNum: 2); + +// reload, synth arg must have corresponding size + +VarGui.load("Path_To_XY", "XY", synth: \buzz ! 4).gui(tryColumnNum: 2); + +:: + + +VarGui only saves slider states, not the Pbind structure (would open a can of worms). So if you had a customized Pbind in the original setup you'd have to pass an appropriate Pbind together with load. This can also be a Pbind other than in the original setup. But if you want to restore you can nearly copy the input of the original cutomization into the pbindmaker method pfuncPbinds ( link::#5b:: ). + + +code:: + +// with no customization save and load also works straightforward +// change slider positions and save + +\buzz.pVarGui.gui; + +// standard pbind is (re-)autogenerated and fits the variables to be set + +VarGui.load("Path_To_XY", "XY", stream: \buzz).gui; + + +// only controls are customized, save and load also works straightforward +// change slider positions, save and reload + +( +[\default, \buzz].pVarGui( + (ctrReplace: { |i| var f = (2*i + 1) * 100, d = 0.2, lo = 0.99, hi = 1.01; + [\freq, [f*lo, f*hi, 0, 0, f*rrand(lo,hi)], \dur, [d*lo, d*hi, 0, 0, d*rrand(lo,hi)] ] }, + post: true, + num: 4), + (ctrReplace: [\freq, [97, 103, \exp, 0, 99], \dur, [0.195, 0.205, 0, 0, 0.2] ]) +).gui(tryColumnNum: 2, allowEnvirBreak: false) +) + +( +VarGui.load("Path_To_XY", "XY", stream: \default ! 4 ++ \buzz) + .gui(tryColumnNum: 2, allowEnvirBreak: false) +) + + +// change slider positions and save + +( +[\buzz, \default].pVarGui(( + ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 8 ], + ctrReplace: [\dur, [0.2, 0.4, \lin, 0.2, 0.2]], + pBefore: [\degree, PLseq(\a), \octave, 3], + quant: 0.2 + ),( + ctrBefore: [\a, { [0, 6, \lin, 1, rrand(0,6) ] } ! 4 ], + ctrReplace: [\dur, [0.1, 0.3, \lin, 0.1, 0.2]], + pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + PLseq(\a), + \octave, Pwhite(5,7) ], + quant: 0.2 + ) +).gui(tryColumnNum: 2, allowEnvirBreak: false); +) + +// restoring pbind structure, note that pfuncPbinds always returns a collection +// and quant arg is separate in VarGui.new and VarGui.load + +( +VarGui.load("Path_To_XY", "XY", + stream: + \buzz.pfuncPbinds(pBefore: [\degree, PLseq(\a), \octave, 3]) ++ + \default.pfuncPbinds(pBefore: [\degree, Pfunc { [0, [0,4], [0,5]].choose } + + PLseq(\a), \octave, Pwhite(5,7) ]), + quant: 0.2 +).gui(tryColumnNum: 2, allowEnvirBreak: false) +) + +:: + + diff --git a/HelpSource/Tutorials/attachments/Idev_suite/Idev_scheme_3.png b/HelpSource/Tutorials/attachments/Idev_suite/Idev_scheme_3.png new file mode 100644 index 0000000000000000000000000000000000000000..2fb4ed6c7be649c9597606d01e21b72a884e1a8f GIT binary patch literal 152759 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 literal 0 HcmV?d00001 diff --git a/HelpSource/Tutorials/attachments/Smooth_Clipping_and_Folding/fold_examples.png b/HelpSource/Tutorials/attachments/Smooth_Clipping_and_Folding/fold_examples.png new file mode 100644 index 0000000000000000000000000000000000000000..4de05c4b462975a5b0343924523ed57f690be723 GIT binary patch literal 100666 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 A=>Px# literal 0 HcmV?d00001 diff --git a/HelpSource/Tutorials/attachments/enum/graph.png b/HelpSource/Tutorials/attachments/enum/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..121e8d5f78be6a8f31c05d69046e0ebea29b081f GIT binary patch literal 6099 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 Tutorials +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous + +DESCRIPTION:: + +Method enum implements a basic backtracking search suited for a number of counting and optimization problems. For specification of search criteria a boolean-valued Function has to be passed. + +note::The method applies to Integers indicating the recursion depth. +Due to the nature of combinatorial problems with an often rapid growth of solutions +and/or enumeration steps with increase of size, it is recommended to start +examples with low numbers to avoid hangs. +:: + +INSTANCEMETHODS:: + + +method::enum +Returns solutions of the problem, which is defined by strong::function::, +as an Array of SequenceableCollections (size = receiver). + +argument::pool + +SequenceableCollection of items to be considered for possible solutions. If type equals 0 the same pool is taken for all indices of possible solutions, if type equals 1 a SequenceableCollection of pools might be passed. The existence of an additional strong::type:: arg is necessary as it might also be desirable to consider SequenceableCollections as single items of possible solutions. + +argument::function + +Boolean-valued Function to be evaluated at strong::currentIndex::. For many applications it is not necessary to evaluate at index 0 (so per default strong::evalAtZero:: set to false), the Function is not evaluated and the item is supposed to be considered as first element of a possible solution. + +From current state the Function is passed the following args to specify search: + +list:: +## strong::item:: - Current item to be checked. + +## strong::currentIndex:: - Current enumeration level, +between 1 (resp. 0 in case strong::evalAtZero:: set to true) and receiver - 1. + +## strong::currentCol:: - Contains current collection of items already chosen +at indices up to strong::currentIndex:: - 1, for efficiency reasons +length of this collection equals receiver and items indexed at +current or higher enumeration level might stem from earlier enumeration steps. + +## strong::indexCol:: - Current collection of indices (of items from strong::pool::) already chosen, +for efficiency reasons length of this collection equals receiver and indices at +current or higher enumeration level might stem from earlier enumeration steps. +:: + +argument::evalAtZero + +Boolean. Determines if strong::function:: will be evaluated at index 0. Defaults to false. + + +argument::type + +Must be 0 or 1. Determines if strong::pool:: should be taken for all items (0, default) or specified per index (1). + +argument::order + +Boolean. Determines if search should follow order of items given in strong::pool:: or a search order is randomly chosen. Defaults to true. For search of a single random solution one would set strong::order:: to false and strong::maxNum:: to 1. + +argument::maxNum + +Integer. Maximum number of solutions to be searched for. Defaults to inf. + + + +SECTION::Example 1: Basic enumerations, Subsets + +code:: +// Listing all tuples from a given collection. +// Note that this kind of complete enumeration +// can be done with method allTuples more efficiently. + + +3.enum([1,2]) + +-> [ [ 1, 1, 1 ], [ 1, 1, 2 ], [ 1, 2, 1 ], [ 1, 2, 2 ], + [ 2, 1, 1 ], [ 2, 1, 2 ], [ 2, 2, 1 ], [ 2, 2, 2 ] ] + + + +// type 1 for specified pool(s) +// receiver must equal size of passed pools + +3.enum([[1,2], [-1,-2], [\a,\b]], type: 1) + +-> [ [ 1, -1, a ], [ 1, -1, b ], [ 1, -2, a ], [ 1, -2, b ], + [ 2, -1, a ], [ 2, -1, b ], [ 2, -2, a ], [ 2, -2, b ] ] + + + +// strictly monotone tuples +// note that function is evaluated only for i > 0, +// so no problem to write i-1 + +3.enum((1..4), { |x,i,col| x > col[i-1] }); + +-> [ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 4 ], [ 2, 3, 4 ] ] + + +// Above is equivalent to the task of finding all +// k-subsets of a given set of n elements. +// The results are lexically ordered. +// For an arbitrary pool, not necessarily numbers, +// you can use the index collection arg within the Function. + +3.enum([\a, \b, \c, \d], { |x,i,col,icol| icol[i] > icol[i-1] }); + +-> [ [ a, b, c ], [ a, b, d ], [ a, c, d ], [ b, c, d ] ] + + +// The number of k-subsets of a set of length n equals n! / k! / (n-k)! +// You might want to check before a complete enumeration: + +~subsetNum = { |n, k| +    var p = 1; +    k.do { |i| p = p * (n - k + i + 1) / (i + 1) }; +    p +}; + +~subsetNum.(18,5) + +-> 8568 + + +// In principle search for tuples with certain features (not only subsets) +// can always be done with using allTuples and filtering out afterwards, +// but this is only feasible for small n. +// E.g. n = 18 and k = 5 requires calculating 1889568 (n**k) tuples first. +// Furthermore method allTuples defaults to a maximum number of 16364 (2**14). +// So (18**5).log2.ceil (21) gives the exponent of 2 to pass + +{ + ((1..18)!5).allTuples((2**21).asInteger) + .select { |y| y.every { |x,i| (i == 0) or: { y[i-1] < y[i] } } }.size.postln; +}.bench + +-> 8568 +time to run: 6.6191733989999 seconds. +6.6191733989999 + + +{ 5.enum((1..18), { |x,i,col| x > col[i-1] }).size.postln; }.bench + +-> 8568 +time to run: 0.10966498400012 seconds. +0.10966498400012 + + +// Tuples without repetitions - +// keep in mind that passed collection is of full length in each step, +// so we have to restrict to the indices up to i-1. +// Writing col[(0..i-1)] means that a new Array is generated in +// every enumeration step. This might be a bottleneck +// with a huge number of steps and could be optimized. + +3.enum((1..4), { |x,i,col| col[(0..i-1)].includes(x).not }); + +-> [[ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 3, 2 ], [ 1, 3, 4 ], [ 1, 4, 2 ], [ 1, 4, 3 ], + [ 2, 1, 3 ], [ 2, 1, 4 ], [ 2, 3, 1 ], [ 2, 3, 4 ], [ 2, 4, 1 ], [ 2, 4, 3 ], + [ 3, 1, 2 ], [ 3, 1, 4 ], [ 3, 2, 1 ], [ 3, 2, 4 ], [ 3, 4, 1 ], [ 3, 4, 2 ], + [ 4, 1, 2 ], [ 4, 1, 3 ], [ 4, 2, 1 ], [ 4, 2, 3 ], [ 4, 3, 1 ], [ 4, 3, 2 ]] + +:: + + +SECTION::Example 2: Melodic Shapes + +code:: +// This follows an idea by Fabrice Mogini +// Given a sequence of pitches, find all melodies of same shape, +// here just understood as up-and-down movement, +// using the given pitches without repetition. + +// The Function has to check whether +// 1.) there are no repetitions +// 2.) the difference to the last item is of same signum as in the original pitch sequence + +// keep in mind that, as always, passed collection is of full length in each step, +// so we have to restrict to the indices up to i-1 + +( +// assuming no pitches repeated +m = [60, 65, 62, 69, 71]; +d = m.differentiate.sign; +f = { |x,i,col| col[(0..i-1)].includes(x).not && ((x - col[i-1]).sign == d[i]) }; +m.size.enum(m, f); +) + +--> [ [ 60, 65, 62, 69, 71 ], [ 60, 69, 62, 65, 71 ], [ 60, 71, 62, 65, 69 ], + [ 65, 69, 60, 62, 71 ], [ 65, 71, 60, 62, 69 ], [ 62, 65, 60, 69, 71 ], + [ 62, 69, 60, 65, 71 ], [ 62, 71, 60, 65, 69 ], [ 69, 71, 60, 62, 65 ] ] + +:: + + +SECTION::Example 3: Partitions of Integers, Scales + +code:: +// list all partitions of a given integer a into n summands + +( +a = 10; +n = 5; + +// storage of partial sums +// ith element will represent sum up to index i-1 + +p = 0!(n+1); + +// Function should also consider case i = 0 + +f = { |x,i,col| + var order = (i > 0).if { x >= col[i-1] }{ true }; + p[i+1] = p[i] + x; + order and: { + (i + 1 < n).if { + // check if partial sums are not too large + (n - i) * x + p[i] <= a + }{ + // partition check at last index i == n-1 + p[i+1] == a + } + } +}; + +// true causes check also at index 0 +5.enum((1..10), f, true); +) + +-> [ [ 1, 1, 1, 1, 6 ], [ 1, 1, 1, 2, 5 ], [ 1, 1, 1, 3, 4 ], [ 1, 1, 2, 2, 4 ], + [ 1, 1, 2, 3, 3 ], [ 1, 2, 2, 2, 3 ], [ 2, 2, 2, 2, 2 ] ] + + + +// in above Function the given integer and the number of summands are hardcoded. +// For a general purpose tool better make a function constructor, +// also build in an arg that determines if solutions should be ascending or not + +( +// Function to make boolean value Function depending on sum a and number of summands n +g = { |a,n,ascending = true| + var p = 0!(n+1); + { |x,i,col| + var order = ((i > 0) && ascending).if { x >= col[i-1] }{ true }; + p[i+1] = p[i] + x; + order and: { + (i + 1 < n).if { + // check if partial sums are not too large + ascending.if { x }{ 1 } * (n - i) + p[i] <= a + }{ + // partition check at last index i == n-1 + p[i+1] == a + } + } + } +}; + +// Function for listing all partitions of number a with n summands + +h = { |a,n,pool,ascending = true| n.enum(pool, g.(a,n,ascending), true) }; +) + + +// partitions of number 10 consisting of 5 summands +// monotone tuples are demanded (so reorder of tuples is neglected) + +h.(10, 5, (1..10)) + +-> [ [ 1, 1, 1, 1, 6 ], [ 1, 1, 1, 2, 5 ], [ 1, 1, 1, 3, 4 ], [ 1, 1, 2, 2, 4 ], + [ 1, 1, 2, 3, 3 ], [ 1, 2, 2, 2, 3 ], [ 2, 2, 2, 2, 2 ] ] + + +// partitions of number 12, taking order into account (not ascending), +// lists all possible scales of a certain number of pitches, +// given as interval arrays + +// this gives all scales of 7 tones with stepwidth from 1 to 3 semitones. +// Result contains rotations of interval arrays that are different, +// e.g. major [2,2,1,2,2,2,1] and dorian [2,1,2,2,2,1,2] + +x = h.(12, 7, (1..3), false); +x.size; + +-> 266 + +:: + + +SECTION::Example 4: Graphs + +code:: +// undirected graph with 9 nodes +:: + +image::attachments/enum/graph.png:: + +code:: +( +// graph represented as array of possible successor nodes +g = [[1,2], [0,3], [0,3,5], [1,2,4,6], [3,7], [2,6], [3,5,7], [4,6,8], [7]]; + +// Function for finding unused nodes to be connected +f = { |x,i,col| col[(0..i-1)].includes(x).not and: { g[col[i-1]].includes(x) } }; + +// search for all paths using each node exactly once +9.enum((0..8), f) +) + +-> [ [ 1, 0, 2, 5, 6, 3, 4, 7, 8 ], [ 4, 3, 1, 0, 2, 5, 6, 7, 8 ], [ 6, 5, 2, 0, 1, 3, 4, 7, 8 ], + [ 8, 7, 4, 3, 1, 0, 2, 5, 6 ], [ 8, 7, 4, 3, 6, 5, 2, 0, 1 ], [ 8, 7, 6, 5, 2, 0, 1, 3, 4 ] ] + + +// give only one random solution - here path of length 8 + +8.enum((0..8), f, order: false, maxNum: 1) + +-> [ [ 0, 1, 3, 4, 7, 6, 5, 2 ] ] + +:: \ No newline at end of file diff --git a/HelpSource/Tutorials/kitchen_studies.schelp b/HelpSource/Tutorials/kitchen_studies.schelp new file mode 100755 index 0000000..d7f172a --- /dev/null +++ b/HelpSource/Tutorials/kitchen_studies.schelp @@ -0,0 +1,1078 @@ +TITLE::kitchen studies +summary::source code of the corresponding fixed media piece +categories:: Libraries>miSCellaneous +related:: Overviews/miSCellaneous, Guides/Introduction_to_miSCellaneous, Classes/PbindFx, Tutorials/Buffer_Granulation, Tutorials/Live_Granulation, Classes/VarGui, Tutorials/DX_suite, Classes/DXMix, Classes/DXMixIn, Classes/DXEnvFan, Classes/DXEnvFanOut, Classes/DXFan, Classes/DXFanOut, Classes/ZeroXBufRd, Classes/TZeroXBufRd, Classes/ZeroXBufWr + + +DESCRIPTION:: + +In 2016 my interest in granular synthesis was focussed on the potential of sequencing arbitrary effects and effect graphs on single grains. This is an application of the class link::Classes/PbindFx::, which I added with miSCellaneous v0.14. As the possibilities are countless – an arbitrary number of effects can be applied on each grain in an arbitrary way: in sequence, in parallel or in any graph order – I started experiments with combinations of at most two effects and sequencing their parameters. At the same time I wanted to share my experiences and document what I was encountering while composing a piece of music. I thought the best approach for that twofold need would be a sequence of small pieces in once, each of them using different effect processings per grain. A piece of such form would not be totally typical for my usual compositional practice, as I tend to favour longer forms with a few contrasting types of material combined in a developing relation, but nevertheless an interesting challenge. As a sound source I took the kitchen sound of five seconds which is already contained in miSCellaneous lib since version 0.7 and used for examples in the link::Tutorials/Buffer_Granulation:: tutorial. + +For the fixed media piece emphasis::kitchen studies:: the audio, resulting from the six sections of code below, has only been cut and slightly mastered with a bit of equalization (as many random components are included, the output will of course vary from one evaluation to the next). Each code section delivers a mixed control by gui (VarGui) and code snippets (Patterns), which reflects my personal experimental preferences with the concerned sounds and might serve as a starting point for the reader's experiments and modifications. Compressed versions of the original piece as a whole and its parts can be found on my website link::http://daniel-mayer.at:: (use a separate browser, players won't work within this window), a further documentation of the compositional process will follow as publication in the artistic research database emphasis::Research Catalogue:: (link::https://www.researchcatalogue.net/profile/show-exposition?exposition=324609::). + +warning:: +numberedList:: + +## Be careful with amplitudes, especially with buffers you haven't granulated before! +Also keep in mind that a granular cloud moving through a buffer can suddenly become louder – this is especially the case with the one percussive sound contained in the used kitchen source sound. Moreover other controls than amp (e.g. buffer position, trigger rate, effect parameters) can cause a raise of amplitude too. + +## I haven't used below setups for live performances. Although all of them work stable for me as they are, in general hangs can occasionally happen with pattern-driven setups. Often this can be tracked down to sequences of extremely short event durations (and/or long grain durations). Where this can happen as a side-effect, thresholds can be built in (e.g. a parameter maxTrigRate). +Another possible source of hangs is careless deep nesting of Patterns where mistakes can easily occur. Starting with clear Pattern structures is recommended – and if more complications are involved: testing without sound first after saving your patch (generating data with a single Stream derived from a Pattern), might be a good idea. +:: +:: + + +note:: +list:: + +## strong::Running the code examples: :: First run the code from chapter link::#Preparations:: - i.e. start server with extended ressources and evaluate the following block of code. Then you can run the example code of each part (but not in parallel). See the comments of link::#1#Part 1::, many of them explain principles, which are used in all other parts too. Similary, gui conventions are pretty much the same for all six parts, see the note on link::#0#common VarGui features:: below. + +## strong::Types of variables: :: For employing the VarGui interface environmental variables and PLx patterns are used. With VarGui every EventStreamPlayer derived from a passed Pattern is run in a separate newly generated Environment, where variables are being set and Streams from Pfuncs and PLx patterns are reading from. See link::Tutorials/Event_patterns_and_Functions::, link::Tutorials/PLx_suite:: and link::Classes/VarGui::. For certain live replacements though, environmental variables in topEnvironment are chosen and for the sake of clarity some interpreter variables are used too. As a result of these two exceptions the six code blocks, as they are, cannot be run in parallel. As each one is producing dense and rich sound structures it was supposed that combining them in realtime would not be the first option anyway (but it could of course be done by rewriting these variables). + +## strong::Buffers: :: All examples below expect mono buffers like the delivered kitchen sound. Buffer paths refering to the included sample suppose that you have moved miSCellaneous lib into the user extensions directory directly (not into a subfolder), if not so or you have moved the sample file somewhere else you'd have to change paths accordingly. + +## strong::Versions: :: For the published version of emphasis::kitchen studies:: I worked on OS 10.6 / SC 3.6.5 and OS 10.8.5 / SC 3.8.0, slight differences in sound might occur with other hardware, operating systems and SC versions. + +:: +:: + + + +SECTION::Preparations + +code:: +// start server with extended ressources + +( +s.options.numPrivateAudioBusChannels = 2048; +s.options.memSize = 8192 * 32; +s.options.maxNodes = 1024 * 4; + +s.reboot; +) + +// Loading the buffer with 'miSCellaneousDirs', +// this searches the most likely extension places for the miSCellaneous folder. +// In case of an extraordinary install situation or if you have removed +// the sound file, pass the concerned path + +// defining SynthDefs: +// 'pos' for single grains +// 'posPlay' for moving buffer position +// fx SynthDefs for PbindFx +// 'leakDC' for leaking DC from summed grains and limiting + +( +b = Buffer.read(s, Platform.miSCellaneousDirs[0] +/+ "Sounds" +/+ "kitchen_sounds_1.wav"); + +// \posPlay is the synthdef for one grain +// args pos and posDev are to be read from a bus, played by a LFO + +// arg pos is relative between 0 and 1 +// arg posDev is absolute (max absolute deviation in seconds from pos) + +SynthDef(\posPlay, { |out = 0, sndBuf = 0, granDur = 0.1, pos = 0, + posDev = 0, rate = 1, att = 0.002, rel = 0.005, pan = 0, amp = 1| + var env, src; + pos = Rand(posDev.neg, posDev) / BufDur.kr(sndBuf) + pos; + src = PlayBuf.ar(1, sndBuf, BufRateScale.kr(sndBuf) * rate, + 1, round(pos * BufFrames.kr(sndBuf)), 1, 2); + env = EnvGen.ar( + Env([0, amp, amp, 0], [att, granDur - att - rel, rel], 0), + doneAction: 2 + ); + OffsetOut.ar(out, Pan2.ar(src, pan) * env); +}, \ir!10).add; + +// posRate of 1 (given by posRateE and posRateM) means +// pos movement through the buffer with original velocity. +// buffer segment is determined by posLo and posHi. +// posDev and pos movement do not depend on buffer length and size of buffer segment ! +// (posRate does, but pos is then mapped to the buffer segment by .linlin) + +// there are four types of movement through the buffer, determined by the arg 'type': +// O: forward +// 1: backward +// 2: forward and backward +// 3: randomly with cubic interpolation + +SynthDef(\pos, { |out = 0, sndBuf = 0, posRateE = 0, posRateM = 1, type = 0, + posLo = 0, posHi = 1, posDevE = 1, posDevM = 0| + var pos, posDev = 10 ** posDevE * posDevM, posRate = 10 ** posRateE * posRateM; + + posRate = posRate / BufDur.kr(sndBuf) / max(0.001, (posHi - posLo)); + pos = Select.kr(type, [ + LFSaw.kr(posRate, 1), + LFSaw.kr(posRate, 1).neg, + LFTri.kr(posRate, 1).neg, + LFDNoise3.kr(posRate) + ]); + pos = pos.linlin(-1, 1, posLo, posHi); + Out.kr(out, [pos, posDev]) +}).add; + + +// leaking DC and limiting summed audio of all grains + +SynthDef(\leakDC, { |out = 0, in| + var sig = In.ar(in, 2); + Out.ar(out, Limiter.ar(LeakDC.ar(sig))); +}).add; + + +// this Function determines enveloping convention: +// absEnv = 1 (true): attack and release times in milliseconds are taken anyway, +// 'overlap' is possibly overriden. +// absEnv = 0 (false): attack and release times in milliseconds are taken only if +// their sum is smaller than grain duration (derived from 'overlap' and 'trigRate'), +// otherwise they are shrunk and their relation is kept. + +d = (); + +d.attRel = { |dict, granDur, att, rel, absEnv = 1| + // times in secs + var sum; + att = att * 0.001; + rel = rel * 0.001; + sum = att + rel; + (sum <= granDur).if { + [att, rel] + }{ + (absEnv == 1).if { + [att, rel] + }{ + [granDur * att, granDur * rel] / sum + } + } +}; +) + +:: + +anchor::0:: +note:: + +strong::Common features of dedicated VarGuis:: + +The slider section always contains two blocks, the lower one is for parameters of the buffer position synth and the upper one is for parameters of the PbindFx. Within the lower block the relative buffer position is determined by parameters 'posLo' and 'posHi'. As the percussive event within the the loaded kitchen sound appears around position 0.3, most position defaults describe a relatively small section around this value. The deviation of position as well as the rate of movement through the buffer are determined by a mantissa-exponent representation each. Finally four types of movement are defined: 0 = forward, 1 = backward, 2 = forward and backward, 3 = random with cubic interpolation. + +Within the upper block there are two or three differently colored sections, separating controls of source and effects (one or two). PbindFx parameters can be directly passed to the source grain player synths (such a 'amp'), but they might also be used to process the actual synth args, e.g. 'absEnv' determines if parameters 'att' and 'rel' are to be taken literally or relative with respect to an "absolute" 'overlap' value (see pseudo method 'attRel' above), this kind of processing is defined within the PbindFx. Not all parameters need to occur in the VarGui instance, they might also be controlled by PL pattern proxies, in that case the pattern sources are defined in topEnvironment later on. + +Amplitude parameters 'amp' occur with grain synths as well as with effect synths, in the latter case they appear with the fx name as suffix in the gui. Their meaning is not the same in all cases, mostly they are understood as amplitudes of the fx-processed signal ("pre-mix"), but they can be applied to the mix too ("post-mix"). In the case of a combined fx/no-fx sequencing a more fine-tuned amplitude control can be achieved with applying a separate gain fx, which is used instead of no effect. For the the sake of clarity this is only done within the last part. + +The EventStreamPlayer derived from the PbindFx (e0 on the right side) and the buffer position synth can be started separately by pressing the green buttons. Note that patches can also be controlled by setting certain PL proxy pattern sources as shown at the bottom of part 1. Regarding the compositional process of emphasis::kitchen studies::, the final sounding result very much depends on the decision which parameters are controlled by pattern sequencing and which ones are controlled by gui-tunable parameters. Such decisions happened during a long process of experimenting which usually started with gui control for all parameters. However for the final version no live-control with sliders has been recorded, parameters were either fixed or algorithmically controlled by patterns. + +:: + +anchor::1:: +SECTION::Part 1 – comb delay plus separate delay modulation + +code:: +// This granulation combines two effects in sequence. +// The same effect chain (fxOrder = [1, 2]) is used for all grains but parameters change. + +( +// comb delay + +SynthDef(\comb, { |out = 0, in, mix = 0.5, amp = 1, maxDelayTime = 0.2, delayTime = 0.02, + decayTime = 1| + var sig, inSig = In.ar(in, 2); + sig = CombL.ar(inSig, maxDelayTime, delayTime, decayTime, amp); + OffsetOut.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + +// modulation of delay +// modInd is a provisional measure for delay modulation in analogy to FM's index + +SynthDef(\delayMod, { |out = 0, in, delayTime = 0.1, maxDelayTime = 2, + modFreq = 0, modIndM = 0, modIndE = -5, mix = 1, amp = 0.1| + var inSig = In.ar(in, 2), sig, modDev; + modDev = 10 ** modIndE * modIndM * modFreq; + sig = DelayC.ar(inSig, maxDelayTime, SinOsc.ar(modFreq, 0, modDev, delayTime), amp); + OffsetOut.ar(out, (1 - mix) * inSig + (sig * mix)); +}).add; + + +// topEnvironment needed for pattern proxies +// the slider variables are set in dedicated environments by VarGui + +t = topEnvironment.push; + +// bus to DC leaker +a = Bus.audio(s, 2); + +// bus for position control +c = Bus.control(s, 2); + +// PLs with envir = t will read from topEnvironment Patterns/Streams (see below) +// other PLs will read slider values + +// produce three minutes audio + +p = Pfindur(180, PbindFx([ + \instrument, \posPlay, + \sndBuf, b, + \out, a, + + \dur, 1 / PL(\trigRate), + \granDur, Pkey(\dur) * PL(\overlap, envir: t), + + \pos, c.subBus(0).asMap, + \posDev, c.subBus(1).asMap, + + \rate, PL(\rate, envir: t), + \amp, PL(\amp), + + \pan, PLseq([-1, 1]) * PL(\panMax), + // determining concrete envelope times (see Function attRel above) + [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) }, + + \fxOrder, PL(\fxOrder, envir: t), + // comb delay time needed for lag in case of no comb + \delayTime_comb, PL(\delayTime_comb, envir: t).collect { |x| d.dt = x; x }, + \lag, Pfunc { |ev| (ev.fxOrder.asArray.includes(1)).if { 0 }{ ev.delayTime_comb } }, + \cleanupDelay, 0.3 + ],[ + \fx, \comb, + \decayTime, PL(\decayTime_comb), + \delayTime, Pfunc { d.dt }, + \mix, PL(\mix_comb), + \amp, PL(\amp_comb), + \cleanupDelay, Pkey(\decayTime) + ],[ + \fx, \delayMod, + \mix, PL(\mix_delayMod), + \amp, PL(\amp_delayMod), + \modIndM, PL(\modIndM_delayMod), + \modIndE, PL(\modIndE_delayMod), + \modFreq, PL(\modFreq_delayMod, envir: t), + \cleanupDelay, 0.1 + ] +)); + +// slider and player control +v = VarGui([ + \att, [1, 200, \lin, 0, 6.97], + \rel, [1, 200, \lin, 0, 8.96], + \absEnv, [0, 1, \lin, 1, 0.0], + \trigRate, [1, 200, \lin, 0, 66.67], + \panMax, [0, 1, \lin, 0, 0.89], + \amp, [0.0, 3, \lin, 0, 1], + + \decayTime_comb, [0.001, 1, \lin, 0, 0.14086], + \mix_comb, [0, 1, \lin, 0, 0.7], + \amp_comb, [0, 3, \lin, 0, 1], + + \modIndE_delayMod, [-6, -2, \lin, 1, -5.0], + \modIndM_delayMod, [0, 10, \lin, 0, 1.5], + \mix_delayMod, [0, 1, \lin, 0, 0.88], + \amp_delayMod, [0, 3, \lin, 0, 1.0] + ],[ + \sndBuf, b.bufnum, + \posLo, [0, 0.99, \lin, 0, 0.2673], + \posHi, [0, 0.99, \lin, 0, 0.3267], + \posDevE, [-6, 0, \lin, 1, -5], + \posDevM, [0.0, 10, \lin, 0, 6.7], + + \posRateE, [-4, 2, \lin, 1, -1], + \posRateM, [0.1, 10, \lin, 0, 0.694], + \type, [0, 3, \lin, 1, 3], + \out, c.index + ], stream: p, synth: \pos +); + +// gui look, color grouping +w = ( + varColorGroups: (0..12).clumps([6, 3, 4]), + synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]), + tryColumnNum: 1, + labelWidth: 130, + sliderWidth: 350, + sliderHeight: 18, + playerHeight: 18 +); +) + + + +// running the patch: evaluate this, +// then in gui start position synth and PbindFx stream by pressing both green buttons + +// Psegs are very practical for defining LFO-like behaviour in SC lang + +( +x = Synth(\leakDC, [\out, 0, \in, a]); + +~overlap = Pseg(PLwrand([0.05, 0.5, 1], [4, 1, 1].normalizeSum), Pwhite(0.5, 1), \sine); +~rate = Pseg(Pwhite(0.05, 1), Pexprand(0.01, 0.5), \sine); +~delayTime_comb = Pseg(PLseq([0.02, 0.002]), Pwhite(8, 15)); +~fxOrder = [1, 2]; +~modFreq_delayMod = Pseg(Pwhite(10, 150), Pwhite(2, 5), \sine); + +v.performWithEnvir(\gui, w) +) + +// while running the patch you can play with sliders and +// exchange the control patterns in top envir on the fly: + +~delayTime_comb = 0.002; +~rate = 0.5; + +~modFreq_delayMod = 70; +~modFreq_delayMod = 50; + +~modFreq_delayMod = Pseg(Pwhite(10, 150), Pwhite(2, 5), \sine); + + +// experiment with fx sequencing: no - comb - (comb > delay modulation) + +~fxOrder = PLseq([0, 1, [1, 2]]); +~fxOrder = Pstutter(Pwhite(1, 10), PLseq([0, 1, [1, 2]])); + + +// after stopping free leakDC synth + +x.free + +:: + + +SECTION::Part 2 – rectangular comb (FFT) + +code:: + +( +// rectangular comb, FFT processing per grain + +SynthDef(\pv_rectComb, { |out = 0, in, numTeeth = 0, width = 0.5, phase = 0, mix = 1, + amp = 0.1| + var chain, inSig = In.ar(in, 2), sig, bufSize = 512, inSigDelayed; + + chain = FFT({ LocalBuf(bufSize) } ! 2, inSig); + chain = PV_RectComb(chain, numTeeth, phase, width); + sig = IFFT(chain) * amp; + // for mix we have to take into account FFT delay + inSigDelayed = DelayL.ar( + inSig, + 0.1, + bufSize / s.sampleRate - (s.options.blockSize / s.sampleRate) + ); + OffsetOut.ar(out, mix * sig + ((1 - mix) * inSigDelayed)); +}).add; + + +t = topEnvironment.push; + +a = Bus.audio(s, 2); +c = Bus.control(s, 2); + +// play two loops with three "interludes" (see Task below) + +p = Pfindur(178, PbindFx([ + \instrument, \posPlay, + \sndBuf, b, + \out, a, + + \dur, 1 / PL(\trigRate), + \granDur, Pkey(\dur) * PL(\overlap), + + \pos, c.subBus(0).asMap, + \posDev, c.subBus(1).asMap, + + \rate, PL(\rate, envir: t), + \amp, PL(\amp), + + \pan, PLseq([-1, 1]) * PL(\panMax), + [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) }, + + \fxOrder, PLseq(\fxOrder, envir: t), + \cleanupDelay, 0.3 + ],[ + \fx, \pv_rectComb, + \mix, PL(\mix_rectComb, envir: t), + \amp, PL(\amp_rectComb), + + \numTeeth, PL(\numTeeth_rectComb, envir: t), + \width, PL(\width_rectComb, envir: t), + \phase, PL(\phase_rectComb, envir: t), + + \cleanupDelay, 0.2 + ] +)); + +// timed pattern control for interludes, done with a Task + +u = Task({ + var times_1 = PLseq([10, 10, 20, 30]).iter; + var times_2 = PLseq([7, 8, 4, 0]).iter; + + loop { + var tm; + ~numTeeth_rectComb = 10; + ~width_rectComb = 0.05; + ~rate = 0.2; + + tm = times_1.next; + tm.wait; + + ~numTeeth_rectComb = Pstutter(Pwhite(5, 30), Pwhite(3, 15)); + ~rate = Pstutter(Pwhite(50, 100), Pwhite(0.3, 0.5)); + ~width_rectComb = Pbrown(0.2, 0.5, 0.02); + + tm = times_2.next; + tm.wait; + } +}.inEnvir(t)); + + +v = VarGui([ + // separate Environments for Task and PbindFx player + [],[ + \att, [1, 200, \lin, 0, 7], + \rel, [1, 200, \lin, 0, 7], + \absEnv, [0, 1, \lin, 1, 0], + \overlap, [0.05, 15, \lin, 0, 3.3], + \trigRate, [1, 200, \lin, 0, 54.73], + + \panMax, [0, 1, \lin, 0, 0.99], + \amp, [0.0, 3, \lin, 0, 0.15], + + \amp_rectComb, [0, 10, \lin, 0, 5.6] + ]],[ + \sndBuf, b.bufnum, + \posLo, [0, 0.99, \lin, 0, 0.2574], + \posHi, [0, 0.99, \lin, 0, 0.3267], + \posDevE, [-6, 0, \lin, 1, -5], + \posDevM, [0.0, 10, \lin, 0, 1.9], + + \posRateE, [-4, 2, \lin, 1, -1], + \posRateM, [0.1, 10, \lin, 0, 5.05], + \type, [0, 3, \lin, 1, 3], + \out, c.index + ], stream: [u, p], synth: \pos +); + +w = ( + varColorGroups: (0..7).clumps([7, 1]), + synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]), + tryColumnNum: 1, + labelWidth: 130, + sliderWidth: 350, + sliderHeight: 18, + playerHeight: 18 +); +) + + +// running the patch: evaluate this, +// then in gui start position synth +// start PbindFx / Task players together by pressing their green buttons with shift-click + +// while running the patch check modified slider values and +// consider pattern replacements as shown in part 1 + + +( +x = Synth(\leakDC, [\out, 0, \in, a]); + +~mix_rectComb = 0.75; +~phase_rectComb = Pstutter(Pwhite(1, 4), Pwhite(0.0, 0.6)); +~fxOrder = [1]; + +v.performWithEnvir(\gui, w) +) + + +// after stopping free leakDC synth + +x.free + +:: + + +SECTION::Part 3 – resampling + +code:: + +( +// fx with "post-mix" amplitude + +SynthDef(\resample, { |out = 0, in, mix = 0.5, amp = 1, resampleRate = 44100| + var sig, inSig = In.ar(in, 2); + sig = Latch.ar(inSig, Impulse.ar(resampleRate)); + OffsetOut.ar(out, ((1 - mix) * inSig + (sig * mix)) * amp); +}).add; + +t = topEnvironment.push; + +a = Bus.audio(s, 2); +c = Bus.control(s, 2); + +p = Pfindur(90, PbindFx([ + \instrument, \posPlay, + \sndBuf, b, + \out, a, + + \dur, 1 / PL(\trigRate, envir: t), + \granDur, Pkey(\dur) * PL(\overlap), + + \pos, c.subBus(0).asMap, + \posDev, c.subBus(1).asMap, + + \rate, PL(\rate, envir: t), + \amp, PL(\amp), + + \pan, PLseq([-1, 1]) * PL(\panMax), + [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) }, + + \fxOrder, PL(\fxOrder, envir: t), + \cleanupDelay, 0.3 + ],[ + \fx, \resample, + \mix, PL(\mix_resample, envir: t), + \amp, PL(\amp_resample), + \resampleRate, PL(\resampleRate_resample, envir: t), + \cleanupDelay, 0.01 + ] +)); + +v = VarGui([ + \att, [1, 200, \lin, 0, 4.98], + \rel, [1, 200, \lin, 0, 4.98], + \absEnv, [0, 1, \lin, 1, 1.0], + \overlap, [0.05, 15, \lin, 0, 3.5], + + \panMax, [0, 1, \lin, 0, 0.93], + \amp, [0.0, 3, \lin, 0, 0.15], + + \amp_resample, [0, 3, \lin, 0, 2.7] + ],[ + \sndBuf, b.bufnum, + \posLo, [0, 0.99, \lin, 0, 0.27], + \posHi, [0, 0.99, \lin, 0, 0.34], + \posDevE, [-6, 0, \lin, 1, -5], + \posDevM, [0.0, 10, \lin, 0, 0.3], + + \posRateE, [-4, 2, \lin, 1, -1], + \posRateM, [0.1, 10, \lin, 0, 3.5], + \type, [0, 3, \lin, 1, 3], + \out, c.index + ], stream: p, synth: \pos +); + +w = ( + varColorGroups: (0..6).clumps([6, 1]), + synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]), + tryColumnNum: 1, + labelWidth: 110, + sliderWidth: 350, + sliderHeight: 18, + playerHeight: 18 +); +) + + +// running the patch: evaluate this, +// then in gui start position synth and PbindFx stream by pressing both green buttons + +// while running the patch check modified slider values and +// consider pattern replacements as shown in part 1 + +( +Synth(\leakDC, [\out, 0, \in, a]); + +~resampleRate_resample = Pn(Plazy { + var freqs = (1..rrand(8, 15)) * rrand(100, 600); + Pseq(freqs, rrand(3, 6)) +}); + +~fxOrder = 1; + +~mix_resample = Pseg( + PLseq([0.0, 0.9]), + // see PS help, examples for "counted embedding" + PLseq([ + PS(Pwhite(2.0, 3), Pwhite(1, 2)), + PS(Pwhite(0.03, 0.05), Pwhite(50, 80)) + ]), + \step +); + +// random quarter tone row +~rate = Pseg(PLshuf((-24..24)/2).midiratio, Pwhite(0.2, 2), \step); + +~trigRate = Pseg(Pwhite(40, 120), Pwhite(0.5, 2), \sine); + +v.performWithEnvir(\gui, w) +) + +// after stopping free leakDC synth + +x.free + +:: + + + +SECTION::Part 4 – spectral complements (FFT) + +code:: +( +// emphasizes / supresses bin range and / or complement +// uses pseudo ugens PV_BinRange and PV_BinGap + +// freqLo and freqHi define the range +// rangeMul is the multiplier for the selected band +// compMul is the multiplier for the rest of the spectrum + +SynthDef(\pv_binRangeBal, { |out = 0, in, freqLo = 80, freqHi = 300, rangeMul = 1, compMul = 1, mix = 1| + var chain, chain_range, chain_comp, inSig = In.ar(in, 2), sig, bufSize = 2048, + lo, hi, binRange, binNum, inSigDelayed; + + binRange = s.sampleRate / bufSize; + binNum = (freqHi - freqLo / binRange).round; + lo = (freqLo / binRange).round; + hi = (freqHi / binRange).round; + + chain = FFT({ LocalBuf(bufSize) } ! 2, inSig); + chain_range = PV_BinRange(chain, lo, hi); + chain_comp = PV_BinGap(chain, lo, hi); + + sig = IFFT(chain_range) * rangeMul + (IFFT(chain_comp) * compMul); + inSigDelayed = DelayL.ar( + inSig, + 0.1, + bufSize / s.sampleRate - (s.options.blockSize / s.sampleRate) + ); + OffsetOut.ar(out, mix * sig + ((1 - mix) * inSigDelayed)); +}).add; + + +t = topEnvironment.push; + +a = Bus.audio(s, 2); +c = Bus.control(s, 2); + +p = Pfindur(200, PbindFx([ + \instrument, \posPlay, + \sndBuf, b, + \out, a, + + \dur, 1 / PL(\trigRate), + \granDur, Pkey(\dur) * PL(\overlap), + + \pos, c.subBus(0).asMap, + \posDev, c.subBus(1).asMap, + + \rate, PL(\rate, envir: t), + \amp, PL(\amp), + + \pan, PLseq([-1, 1]) * PL(\panMax), + [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) }, + + \fxOrder, PL(\fxOrder, envir: t), + \cleanupDelay, 0.3 + ],[ + \fx, \pv_binRangeBal, + \mix, PL(\mix_pv_binRangeBal), + + \freqLo, PL(\freqLo_pv_binRangeBal, envir: t), + \freqHi, Pkey(\freqLo) + PL(\freqRange_pv_binRangeBal, envir: t), + + // multipliers for spectral band and complement are given as tupel 'muls' + \muls, PL(\muls_pv_binRangeBal, envir: t), + \rangeMul, Pkey(\muls).collect(_[0]), + \compMul, Pkey(\muls).collect(_[1]), + + \cleanupDelay, 0.2 + ] +)); + +v = VarGui([ + \att, [1, 200, \lin, 0, 3], + \rel, [1, 200, \lin, 0, 3], + \absEnv, [0, 1, \lin, 1, 0], + + \overlap, [0.1, 2, \lin, 0, 1.45], + \trigRate, [1, 200, \lin, 0, 118.41], + + \panMax, [0, 1, \lin, 0, 0.88], + \amp, [0.0, 3, \lin, 0, 0.9], + + \mix_pv_binRangeBal, [0, 1, \lin, 0, 1] +],[ + \sndBuf, b.bufnum, + \posLo, [0, 0.99, \lin, 0, 0.21], + \posHi, [0, 0.99, \lin, 0, 0.34], + \posDevE, [-6, 0, \lin, 1, -5], + \posDevM, [0.0, 10, \lin, 0, 1.0], + + \posRateE, [-4, 2, \lin, 1, -2], + \posRateM, [0.1, 10, \lin, 0, 2.278], + \type, [0, 3, \lin, 1, 3], + + \out, c.index + ], stream: p, synth: \pos +); + +w = ( + varColorGroups: (0..7).clumps([7, 1]), + synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]), + tryColumnNum: 1, + labelWidth: 130, + sliderWidth: 350, + sliderHeight: 18, + playerHeight: 18 +); +) + + +// running the patch: evaluate this, +// then in gui start position synth and PbindFx stream by pressing both green buttons + +// while running the patch check modified slider values and +// consider pattern replacements as shown in part 1 + +( +Synth(\leakDC, [\out, 0, \in, a]); + +~fxOrder = 1; + +// double source grain in octave distance +~rate = [0.15, 0.3]; + +// pattern for lower bound of spectral band +~freqLo_pv_binRangeBal = Pn(Plazy { + var x = { exprand(200, 4000) } ! rrand(2, 4); + Pseq(x, rrand(5, 15)); +}); + +~freqRange_pv_binRangeBal = 2500; + +// this is a bit more complicated +// polyrhythm for multipliers of band and complement +// it becomes more clear when applying trace to the following patterns + +~zeroOneSeqTupleStream = PLshufn([ + [[0, 1, 1], [0, 0, 1, 1]], + [[0, 1, 1], [0, 1, 1, 1]], + [[0, 0, 1], [0, 0, 1, 1]], + [[0, 0, 1], [0, 1, 1, 1]], +]).iter; + +~muls_pv_binRangeBal = Pn(Plazy ({ + var tuple = ~zeroOneSeqTupleStream.next; + if (0.5.coin) { tuple = tuple.reverse }; + if (0.5.coin) { + tuple[0] = tuple[0].reverse; + tuple[1] = tuple[1].reverse; + }; + Pfinval([500, 400, 300].choose, Ptuple([ + PLseq(tuple[0]), + PLseq(tuple[1]) + ])) +}.inEnvir)); + +v.performWithEnvir(\gui, w) +) + +// after stopping free leakDC synth + +x.free + +:: + + + +SECTION::Part 5 – frequency shift with feedback + +code:: + +( +// frequency shift with feedback +// "post-mix" fx amplitude + +// fx with feedback obviously needs envelope ! + +SynthDef(\freqShift, { |out = 0, in, mix = 1, freq = 0, fbAmp = 0, + granDur = 0.1, att = 0.01, rel = 0.01, amp = 0.1| + var inSig = In.ar(in, 2), sig, fb, env; + sig = inSig + (fbAmp * LocalIn.ar(2)); + sig = Limiter.ar(sig); + sig = FreqShift.ar(sig, freq); + LocalOut.ar(sig); + + sig = LPF.ar(sig, 10000); + // delayed attack is functioning as additional feedback control + env = EnvGen.ar(Env([0, 0, 1, 1, 0], [0.01, att, granDur - att - rel, rel]), doneAction: 2); + OffsetOut.ar(out, (mix * sig + ((1 - mix) * inSig)) * amp * env); +}).add; + +t = topEnvironment.push; + +a = Bus.audio(s, 2); +c = Bus.control(s, 2); + +p = PbindFx([ + \instrument, \posPlay, + \sndBuf, b, + \out, a, + + \dur, 1 / PL(\trigRate), + \granDur, Pkey(\dur) * PL(\overlap), + + \pos, c.subBus(0).asMap, + \posDev, c.subBus(1).asMap, + + \rate, PL(\rate, envir: t), + \amp, PL(\amp), + + \pan, PLseq([-1, 1]) * PL(\panMax), + [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) }, + + // envelope data to be shared with fx + \do, Ptuple([Pkey(\granDur), Pkey(\att), Pkey(\rel)]) + .collect { |x| t[\share] = x }, + + \fxOrder, PL(\fxOrder, envir: t), + + \cleanupDelay, Pfunc { |ev| max(0.2, ev[\granDur] - ev[\dur]) } + ],[ + \fx, \freqShift, + \mix, PL(\mix_freqShift), + \amp, PL(\amp_freqShift), + [\granDur, \att, \rel], Pfunc { t[\share] }, + \granDur, Pkey(\granDur) * 0.9, + \freq, PL(\freq_freqShift, envir: t), + \fbAmp, PL(\fbAmp_freqShift, envir: t), + + \cleanupDelay, 0.5 + ] +); + + +v = VarGui([ + \att, [1, 200, \lin, 0, 3], + \rel, [1, 200, \lin, 0, 7], + \absEnv, [0, 1, \lin, 1, 1.0], + + \overlap, [0.05, 15, \lin, 0, 6.927], + \trigRate, [1, 200, \lin, 0, 24.88], + + \panMax, [0, 1, \lin, 0, 0.84], + \amp, [0.0, 1, \lin, 0, 0.06], + + \mix_freqShift, [0, 1, \lin, 0, 0.54], + \amp_freqShift, [0.1, 2, \lin, 0, 0.3] +],[ + \sndBuf, b.bufnum, + \posLo, [0, 0.99, \lin, 0, 0.21], + \posHi, [0, 0.99, \lin, 0, 0.34], + \posDevE, [-6, 0, \lin, 1, -5], + \posDevM, [0.0, 10, \lin, 0, 0.5], + + \posRateE, [-4, 2, \lin, 1, 0], + \posRateM, [0.1, 10, \lin, 0, 1.486], + \type, [0, 3, \lin, 1, 3], + + \out, c.index + ], stream: p, synth: \pos +); + + +w = ( + varColorGroups: (0..8).clumps([7, 2]), + synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]), + tryColumnNum: 1, + labelWidth: 130, + sliderWidth: 350, + sliderHeight: 18, + playerHeight: 18 +); +) + + +// running the patch: evaluate this, +// then in gui start position synth and PbindFx stream by pressing both green buttons + +// while running the patch check modified slider values and +// consider pattern replacements as shown in part 1 + +( +Synth(\leakDC, [\out, 0, \in, a]); + +~freq_freqShift = Pstutter(Pwhite(10, 50), Pwhite(-200, 50, 1)); +~fbAmp_freqShift = Pstutter(Pstutter(Pwhite(2, 5), Pwhite(1, 2)), PLseq([1, -2])); +~fxOrder = [1]; + +~rate = Pn(Plazy { + Pseries(exprand(0.3, 0.7), rrand(0.02, 0.1), rrand(5, 20)); +}) * 0.8; + +v.performWithEnvir(\gui, w) +) + +// after stopping free leakDC synth + +x.free + + +:: + +SECTION::Part 6 – band pass + +code:: + +( +// band pass +// "post-mix" fx amplitude + +SynthDef(\bpf, { |out = 0, in, freq = 440, rq = 0.1, amp = 1, mix = 1| + var sig, inSig = In.ar(in, 2); + sig = BPF.ar(inSig, freq, rq); + OffsetOut.ar(out, (mix * sig + ((1 - mix) * inSig)) * amp); +}).add; + +// gain as fx for better control of balancing when sequencing grains with and without band pass + +SynthDef(\gain, { |out = 0, in, amp = 1| + var inSig = In.ar(in, 2); + OffsetOut.ar(out, inSig * amp); +}).add; + + +t = topEnvironment.push; + +a = Bus.audio(s, 2); +c = Bus.control(s, 2); + +// duration defined by 'rate' with Pfinval +p = PbindFx([ + \instrument, \posPlay, + \sndBuf, b, + \out, a, + + \dur, 1 / PL(\trigRate), + \granDur, Pkey(\dur) * PL(\overlap), + + \pos, c.subBus(0).asMap, + \posDev, c.subBus(1).asMap, + + \rate, PL(\rate, 1, envir: t), + \amp, PL(\amp), + + \pan, PLseq([-1, 1]) * PL(\panMax), + [\att, \rel], Pfunc { |ev| d.attRel(ev[\granDur], ~att, ~rel, ~absEnv) }, + + \fxOrder, PL(\fxOrder, envir: t), + \cleanupDelay, 0.3 + ],[ + \fx, \gain, + \amp, PL(\amp_gain), + + \cleanupDelay, 0.01 + ],[ + \fx, \bpf, + \freq, PL(\freq_bpf, envir: t), + \rq, PL(\rq_bpf), + \mix, PL(\mix_bpf), + \amp, PL(\amp_bpf), + + \cleanupDelay, 0.01 + ] +); + +v = VarGui([ + \att, [1, 200, \lin, 0, 4.98], + \rel, [1, 200, \lin, 0, 4.98], + \absEnv, [0, 1, \lin, 1, 1.0], + \overlap, [0.05, 15, \lin, 0, 6.7775], + + \trigRate, [1, 200, \lin, 0, 176.12], + \panMax, [0, 1, \lin, 0, 0.83], + \amp, [0.0, 3, \lin, 0, 0.75], + + \amp_gain, [0.0, 3, \lin, 0, 0.36], + + \rq_bpf, [0.01, 1, \lin, 0, 0.0397], + \mix_bpf, [0, 1, \lin, 0, 0.91], + \amp_bpf, [0, 1, \lin, 0, 2.7], + ],[ + \sndBuf, b.bufnum, + \posLo, [0, 0.99, \lin, 0, 0.2574], + \posHi, [0, 0.99, \lin, 0, 0.4059], + \posDevE, [-6, 0, \lin, 1, -4], + \posDevM, [0.0, 10, \lin, 0, 1.0], + + \posRateE, [-4, 2, \lin, 1, -1], + \posRateM, [0.1, 10, \lin, 0, 0.892], + \type, [0, 3, \lin, 1, 3], + \out, c.index + ], stream: p, synth: \pos +); + +w = ( + varColorGroups: (0..10).clumps([8, 3]), + synthColorGroups: (0..8).clumps([1, 2, 2, 2, 1, 1]), + tryColumnNum: 1, + labelWidth: 130, + sliderWidth: 350, + sliderHeight: 18, + playerHeight: 18 +); +) + + +// running the patch: evaluate this, +// then in gui start position synth and PbindFx stream by pressing both green buttons + +// while running the patch check modified slider values and +// consider pattern replacements as shown in part 1 + +( +Synth(\leakDC, [\out, 0, \in, a]); + +// "octave arpeggio" bandpass frequencies, interleaved (PS with repeats = 1) +// check other relations, repetition numbers and fxOrder sequences + +~freq_bpf = PLseq([ + PS(Pstutter(3, Pseg(Pwhite(200, 7000), Pwhite(0.5, 2))) * PLseq([0.5, 1, 2]), 1), + PS(Pstutter(2, Pseg(Pwhite(200, 7000), Pwhite(0.5, 2))) * PLseq([0.5, 1, 2]), 1) +]); + +// start with 1 ensures that we don't have filter only in single channel +~fxOrder = PLseq([1, 2, 2, 1]); + +// development by descending rate "chords" + +~rate = Pseq([ + Pfinval(5582, + Pstutter( + PLseq([120, 80, 80]), + Pexprand(0.3, 1.5).clump(PLshufn((1..3)) * 2 + 1) + ).flatten + ), + Pfinval(5582, + Pstutter( + PLseq([120, 80, 80]), + Pexprand(0.3, 0.6).clump(PLshufn((1..3)) * 2 + 1) + ).flatten + ), + Pfinval(15000, + Pstutter( + PLseq([120, 80, 80]), + Pexprand(0.1, 0.2).clump(PLshufn((1..3)) * 2 + 1) + ).flatten + ) +]); + +v.performWithEnvir(\gui, w) +) + +// after stopping free leakDC synth + +x.free + +:: + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..82fa1da --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.txt b/README.txt new file mode 100755 index 0000000..356f2a4 --- /dev/null +++ b/README.txt @@ -0,0 +1,448 @@ + +====================================================================================== +miSCellaneous - a library of SuperCollider extensions (c) 2009-2020 Daniel Mayer +====================================================================================== + +Version 0.23 contains these class and help files (SCDoc and old HTML system): + + +1. Guide "Introduction to miSCellaneous": recommended starting point. + +2. VarGui: a slider / player gui to set envir variables and synth controllers and + play synths, event patterns and tasks, see also "VarGui shortcut builds". + "HS with VarGui", a specific tutorial about the combination of HS family and VarGui. + +3. General tutorials: "Event patterns and LFOs" contains an overview of + related LFO-control setups with event patterns. "Event patterns and Functions" + is treating requirements of the control of EventStreamPlayers with VarGui. + "Event patterns and array args" focusses on passing arrays to synths with patterns. + "enum" is a general enumeration method suited for many combinatorial problems such as + listing subsets, partitions of integers, searching for paths within graphs etc. + +4. "PLx suite", dynamic scope variants of common Pattern classes for convenient + replacement. Can be used for shorter writing of Pbinds to be played with VarGui + and / or live coding, see "PLx and live coding with Strings". + PLbindef and PLbindefPar as subclasses of Pdef allow replacement of + key streams in shortcut pseudomethod syntax. + +5. PSx stream patterns, Pattern variants that have a state and can remember their + last values. Can be used for recording streams and event streams (PS), + data sharing between event streams (PSdup), comfortable defining of subpatterns + with counted embedding, defining of recursive (event) sequences (PSrecur) and + building loops on given Patterns/Streams with a variety of options, also for + live interaction (PSrecur). + +6. Event pattern classes for use with effects: PbindFx can handle arbitrary effect + graphs per event, PmonoPar and PpolyPar follow the Pmono paradigm. + The tutorial "kitchen studies" contains the documented source code of a + fixed media piece using PbindFx for granulation. + +7. Further Pattern classes: PlaceAll, Pshufn, PsymNilSafe. + PSPdiv is a dynamic multi-layer pulse divider based on Pspawner. + +8. "Buffer Granulation", a tutorial covering different approaches of implementing + this synthesis method in SC (server versus language control, mixed forms), + examples with VarGui, language-driven control with PLx suite patterns. + The tutorial "Live Granulation" summarizes direct options without + explicit use of a buffer. + +9. A family of classes for the use of synth values in Pbind-like objects. + Take Working with HS and HSpar as a starting point, see also + HS, PHS, PHSuse, HSpar, PHSpar, PHSparUse, PHSplayer, PHSparPlayer, PHSusePlayer. + +10. EventShortcuts, a class for user-defined keywords for events and event patterns. + The tutorial "Other event and pattern shortcuts" collects some further abbreviations, + e.g. functional reference within events and event patterns, similar to Pkey. + +11. An implementation of Xenakis' Sieves as class and pattern family, see + "Sieves and Psieve patterns" for an overview and examples. + +12. FFT pseudo ugens for defining ranges by bin index: PV_BinRange and PV_BinGap. + +13. Smooth Clipping and Folding, a suite of pseudo ugens. + +14. DX, a suite of pseudo ugens for crossfaded mixing and fanning according to + demand-rate control. + +15. Idev suite, patterns and drate ugen searching for numbers with integer distance from a + source pattern / signal. + +16. Nonlinear dynamics: Fb1 for single sample feedback / feedforward and GFIS for + generalized functional iteration synthesis. + Fb1_ODE for ordinary differential equation integration. + +17. ZeroXBufWr, ZeroXBufRd, TZeroXBufRd: pseudo ugens for analysis of zero crossings and + playing sequences of segments between them with demand rate control. + + +Many of the examples here are using patterns, resp. event patterns but do not cover +their basic concepts. For a detailled description of SC's sequencing capabilities see +James Harkins' Practical Guide to Patterns (PG_01_Introduction), the tutorial +Streams-Patterns-Events (1-7) and the Pattern help files +(Pattern, Pbind and the type-specific ones). + +VarGui handles namespace separation by using different Environments. +So a gui for control of parametrized families of different types of objects can be +built on the fly (e.g. a number of EventStreamPlayers from a single Pbind definition +with snippets of functional code, a number of Function plots from a single +parametric function definition etc.). +See Environment and Event helpfiles for the underlying concepts and +"Event patterns and Functions" and "PLx suite" for their application to +event patterns resp. EventStreamPlayers. + + +Requirements + +At least SuperCollider version 3.6 but newer versions are recommended, +with 3.6 you'd have to use Qt GUI kit, which is the only option anyway from 3.7 onwards. +Unable to test on 3.5 anymore, code might work, anyway old help is still supported. + +If you still use Cocoa or SwingOSC with these old SC versions, +you can take miSCellaneous 0.15b and add classes and help files from a +newer version of miSCellaneous. + +For using VarGui with EZSmoothSlider and EZRoundSlider you would need to +install Wouter Snoei's wslib Quark, one buffer granulation +example using Wavesets depends on Alberto de Campo's Wavesets Quark. + +I tested examples on SC versions 3.6 - 3.11, +on OS 10.8 - 10.13, Ubuntu 12.04 and Windows 7, 10; +though not every platform / OS version / SC version combination. + + +SCDoc issues (SC 3.10) + +With SC 3.10.0 - SC 3.10.2 there are issues with evaluating code in the +help file examples (double evaluation). +For these versions you'd rather copy the help file code +into scd files and run it there. +Double evaluation has been fixed with 3.10.3 (August 2019). +With SC updates to 3.10 it might happen that help file examples are invisible. +In that case delete the Help folder which resides in one of these places, depending +where you have installed: + +Platform.userAppSupportDir; +Platform.systemAppSupportDir; + +Then restart SC. + + +Installation + +By version 0.17 you can install either via the quarks extension management system or a +downloaded zip from GitHub or my website. +Both methods shouldn't be combined, e.g. if you have already done a manual install +before by placing a miSCellaneous folder in the Extensions folder, then remove +it from there before the quarks install. + +1.) Installation via Quarks + +This requires a SC version >= 3.7, see the recommended ways to install here: + +http://doc.sccode.org/Guides/UsingQuarks.html +https://github.com/supercollider-quarks/quarks + +After a install of a newer version of miSCellaneous do a SCDoc update by + +SCDoc.indexAllDocuments(true) + + +2.) Manual installation from a downloaded zip + +You can download the newest version from + +https://github.com/dkmayer/miSCellaneous_lib + +and the newest and all previous versions from here: + +http://daniel-mayer.at + +Copy the miSCellaneous folder into the Extensions folder and recompile +the class library or (re-)start SC. If the Extensions folder doesn't exist +you'd probably have to create it yourself. Check SC help for platform-specific +conventions (or changes) of extension places. + +Typical user-specific extension directories: + +OSX: ~/Library/Application Support/SuperCollider/Extensions/ +Linux: ~/.local/share/SuperCollider/Extensions/ + +Typical system-wide extension directories: + +OSX: /Library/Application Support/SuperCollider/Extensions/ +Linux: /usr/share/SuperCollider/Extensions/ + +You can check Extension directories with + +Platform.userExtensionDir; +Platform.systemExtensionDir; + +On Windows see the README file of SC for the recommended extensions path. +On Windows and OSX you might have to make the concerned folders visible, +if they aren't already. The miSCellaneous folder should be placed directly +into the Extensions folder, not into a subfolder. + +After a install of a newer version of miSCellaneous do a SCDoc update by + +SCDoc.indexAllDocuments(true) + + +License + +miSCellaneous is distributed under the GNU Public License in accordance +with SuperCollider. You should have received a copy of the +GNU General Public License along with this program; +if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Contact + +Email: daniel-mayer@email.de +URL: http://daniel-mayer.at + + +Credits + +Many thanks to James McCartney for developing SuperCollider, +Alberto de Campo for showing me its capabilities, +Wouter Snoei for his nice slider classes in wslib, +Nathaniel Virgo for his suggestions for feedback, +David Pirrò for his hints concerning ODE integration, +James Harkins for his remarks on many things and +the whole community for contributions and hints ! + + +===================================================================================== + + +History + + +v0.23 2020-04-19 + + .) ZeroXBufWr, ZeroXBufRd, TZeroXBufRd: playing half wavesets with demand rate control + .) Remove doubled method lincurve_3_9, which caused a warning without harm + .) AddEventTypes_PbindFx: use store instead of writeDefFile in private methods + .) Minor fixes in help files + + +v0.22 2019-08-14 + + .) Fb1_ODE and related: ordinary differential equation integration + .) Fb1: now also runs at control rate, Fb1.new is equivalent to Fb1.ar + .) Fb1: minor change of forced graph ordering + .) PbindFx: accept instruments/fxs given as Strings in pbindData key/value pairs + .) Minor fixes in help files + + +v0.21 2018-07-25 + + .) Fb1: single sample feedback / feedforward + .) GFIS: generalized functional iteration synthesis + .) Redefined variables in Sieve, PSrecur and PSPdiv to enable inlining + .) Minor fixes in help files + + +v0.20 2018-05-21 + + .) Idev suite, search for numbers with integer distance from a source + .) Bug fix in Integer method lcmByFactors + .) Minor fixes in help files + + +v0.19 2017-11-22 + + .) DX, a suite of pseudo ugens for crossfaded mixing and fanning + .) Minor adaption of PbindFx event type + .) Minor fixes in help files + + +v0.18 2017-09-26 + + .) PLbindef / PLbindefPar: new features and implementation + .) Minor fixes in PV_BinGap and PV_BinRange + .) Minor fixes in help files + + +v0.17 2017-08-21 + + .) Smooth Clipping and Folding, a suite of pseudo ugens + .) Added MIDI learning feature for VarGui slider control + .) Platform.miSCellaneousDirs, search for miSCellaneous folder + .) Adapted PV_BinRange and PV_BinGap to do multichannel expansion + .) Exchanged graphic examples in VarGui help (Qt now) + .) Minor fixes in help files + .) First version released via GitHub and as Quark + + +v0.16 2017-03-03 + + .) Added PSPdiv, a dynamic multi-layer pulse divider based on Pspawner + .) Added tutorial: Live Granulation + .) Dropped miSCellaneous' b-branch: Cocoa and SwingOSC no longer supported + .) Replaced OSCpathResponder by OSCFunc in classes VarGuiPlayerSection, + HelpSynth and HelpSynthPar + .) Minor fixes in help files + + +v0.15 2017-01-04 + + .) Guide "Introduction to miSCellaneous" + .) kitchen studies: source code of the corresponding fixed media piece + .) PV_BinRange, PV_BinGap: FFT pseudo ugens for defining bin ranges + .) PbindFx help: new example 4a for defining implicit fx parallelism + .) Minor fixes (help files, typos) + .) Complemeting history information (tutorials) + + +v0.14 2016-08-25 + + .) Sieves and Psieve patterns, an implementation of Xenakis' sieves + .) PLbindef / PLbindefPar: replacement of key streams in pseudomethod syntax + .) Tutorial: PLx and live coding with Strings + .) PsymNilSafe, method symplay: avoid hangs with nil input + .) EventShortcuts: reworking of replacement, new method eventShortcuts + .) PbindFx: reworking of bus match check + .) Minor fixes (help files, typos) + + +v0.13 2015-10-28 + + .) PbindFx: Event pattern class for effect handling on per-event base + .) Minor fixes (help files, typos) + + +v0.12 2015-05-03 + + .) PmonoPar, PpolyPar: + Event pattern classes for parallel setting streams and effect handling + .) PSloop: Pattern to derive loops from a given Pattern + .) Reworked replacing options of PL list patterns: cutItems arg. + .) PLn: PLx Pattern for replacing with protecting periods + .) Added PLxrand, PLx version of Pxrand + .) Changed implementations of PStream (PS) and PSrecur, + now the MemoRoutine isn't instantiated before embedding, + this enables use of PSx patterns with VarGui + .) Fixed a bug in PL list patterns (PL_PproxyNth) that caused too early + replacements in certain cases + .) Added method bufSeq for PStream + .) Added missing help file of PLtuple + .) Minor fixes (help files, typos) + + +v0.11 2015-02-02 + + .) Tutorial: Event patterns and array args + + +v0.10 2014-10-06 + + .) Split into branches 0.10a (3.7 onwards) and 0.10b (from 3.4 up to 3.6.x), + with SC 3.7 SwingOSC and Cocoa aren't supported anymore. + .) Class EventShortcuts and tutorial "Other event and pattern shortcuts" + + +v0.9 2014-02-18 + + .) PSx stream patterns (classes and tutorial), based on class MemoRoutine + .) Buffer Granulation Tutorial: new examples (1c - 1e, 3d) + .) VarGui save dialog fix (was broken with 3.6) + .) Minor fixes (help files, typos) + + +v0.8 2013-05-05 + + .) Enumeration tutorial: method enum + + +v0.7.1 2013-04-28 + + .) Fix in PLseries and PLgeom + + +v0.7 2012-08-31 + + .) Buffer Granulation tutorial file + .) VarGui + .) Support of wslib slider classes EZSmoothSlider and EZRoundSlider + .) Color grouping options for synth and envir variable control + .) Adapting EZSlider to ControlSpec step size + (fixes certain rounding and jitter issues) + .) Multiple slider handling with modifier keys: fixes and cleanup + + +v0.6 2012-05-19 + + .) PLx dynamic scope pattern suite + .) Implementation of a number of common Patterns as PLx classes + .) Tutorial PLx suite + .) Changing examples in some previous help files accordingly + .) Pstream, PlaceAll, Pshufn + + +v0.5 2012-03-18 + + .) VarGui shortcut build methods + .) Use of SynthDef metadata and global ControlSpecs + .) Tutorial VarGui shortcut builds + .) Automatic Pbind generation + .) Minor fixes in VarGui init procedure + + +v0.4 2011-12-27 + + .) VarGui support for HS family classes + .) Tutorial HS with VarGui + .) VarGui takes addAction as slider hook + .) Linux check (tested on Ubuntu): + .) Fixed system time issue in HS family + .) Specified VarGui appearance default parameters for platform and gui kit + .) Supports SCDoc, the new SC help system + .) Tutorial Event Patterns and Functions + .) Tutorial Event patterns and LFOs + .) Play methods of PHSx and PHSxPlayer now also take numbers as quant arg + .) Minor fixes in HS family + + +v0.4beta 2011-08-18 + + .) VarGui relaunch: + .) Player section for Synths, EventStreamPlayers and Tasks + .) Different player modes + .) Button colors and background colors reflecting playing states + .) Handling groups of players and sliders with modifier keys + .) Player action by mouse down or up (currently cocoa only) + .) Variables can be set in different environments + .) Latency setting, global and for synth player message bundling + .) GUI appearance customization in size, arrangement and color + .) Many other changes, e.g. arg conventions + .) Private extension methods get prefix miSC_ + + +v0.3 2010-10-21 + + .) VarGui: + .) Arrayed synth control supported + .) Slider update methods added + .) Save dialog now uses unified gui class Dialog + .) Again compiling with SC 3.3 and 3.3.1 + + +v0.2 2010-09-18 + + .) Minor adaptions to SC 3.4 + .) Fixed time shifting issue + + +v0.1 2009-11-24 + + .) VarGui, interface for envir variable and synth arg control + .) HS / HSpar etc.: classes for the use of synth values in Pbind-like objects + .) Tutorial Working with HS and HSpar + + +===================================================================================== + + + \ No newline at end of file diff --git a/Sounds/kitchen_sounds_1.wav b/Sounds/kitchen_sounds_1.wav new file mode 100644 index 0000000000000000000000000000000000000000..800b69c4e4c220921e7e2227813cc6e7f7908d2b GIT binary patch literal 461824 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 J9QbQE@IM!+gxvrD literal 0 HcmV?d00001 diff --git a/miSCellaneous_lib.quark b/miSCellaneous_lib.quark new file mode 100644 index 0000000..bd5e26f --- /dev/null +++ b/miSCellaneous_lib.quark @@ -0,0 +1,13 @@ +( + name: "miSCellaneous_lib", + author: "Daniel Mayer", + summary: "Extensions and tutorials: patterns, fx sequencing, granulation, demand rate controlled (half) wavesets, wave folding, sieves, combined lang and server gui control, live coding, single sample feedback, ordinary differential equation audification, generalized functional iteration synthesis", + version: "0.23.0", + since: "2009", + schelp: "miSCellaneous.schelp", + helpdoc: "miSCellaneous.html", + isCompatible: { Main.versionAtMost(3, 5).not }, + organisation: "Institute of Electronic Music and Acoustics Graz (IEM)", + country: "Austria", + url: "http://daniel-mayer.at/software_en.htm" +)

    Part of: miSCellaneous