From 1d8cf9ae43f23d8dcbbf73ee90a7ba10399ee96b Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:05:21 +1100 Subject: [PATCH 1/9] ndef --- README.md | 106 ++++++++++++++++++++++++++++++++++++++++------------ voltage.scd | 12 ++++++ 2 files changed, 95 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 842b9eb..b7ab7c8 100644 --- a/README.md +++ b/README.md @@ -2,43 +2,94 @@ # SuperDirt Voltage -A small set of SuperDirt synths and Tidal helpers to control modular synths. No MIDI required! +A small set of SuperDirt synths and Tidal helpers to control modular synths. No +MIDI required! **2023 updates:** +- nDef synths - Added `saw`, `lfo` triggered LFOs - `amp` now controls the scale of `gate`, `voltage`, `saw`, `ar`, and `lfo` --- +### nDefs + +Defining `nDef` synths provide a constant signal between cycles and +instructions. + +```c +Ndef(\cv_np).source = \nPitch; +Ndef(\cv_np).play(0); +~dirt.soundLibrary.addSynth(\cv, (play: { + var latency = (~latency ? 0); + var freq = ~freq; + var channel = ~channel; + var portamento = ~portamento; + + Ndef(\cv_np).wakeUp; // make sure the Ndef runs + + thisThread.clock.sched(latency - 0.025, { + Ndef(\cv_np).set(\portamento, portamento); + Ndef(\cv_np).set(\channel, channel); + Ndef(\cv_np).set(\freq, freq); + }); +}) +); +``` + +You will need to define a separate `nDef` for each instance you would like to +use. + +```haskell +-- you can select pitch by number +d1 $ n "20" # s "cv" + +-- or by note name +d1 $ n "c3" # s "cv" + +-- change channel output and/or portamento +d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 +``` + +--- + +The following synths, while easier to use, create a new cv instance each cycle. +This can result in short gaps/breaks in between cycles. You can use `nDef`'s +above to remedy this. + ### Pitch, with octave quantisation -``` +```haskell -- change notes per octave on each cycle d1 $ pitch "0 10 8 1" # octave "<12 31 8>" # x 1 ``` -`pitch` allows a pattern of note values. `octave` sets the amount of notes per octave. The pitch and scale values will be converted to `1v/octave`. Both `pitch` and `octave` can be sequenced for some microtonal madness... +`pitch` allows a pattern of note values. `octave` sets the amount of notes per +octave. The pitch and scale values will be converted to `1v/octave`. Both +`pitch` and `octave` can be sequenced for some microtonal madness... -`glide` accepts a strengh (in semitones, relative to scale), a rate (in step length). +`glide` accepts a strengh (in semitones, relative to scale), a rate (in step +length). -``` +```haskell -- glide to pitch d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 1 # glide 12 0.5 ``` ### Gate -``` +```haskell -- sequence gate inputs d2 $ gate "0 1 0 0 1 1 1" # x 2 ``` -`gate` will take a 0/1 pattern and return +5v signals for the `1` values. Use `-1` if you need a -5v. +`gate` will take a 0/1 pattern and return +5v signals for the `1` values. Use +`-1` if you need a -5v. ### Voltage automation -``` +```haskell -- create stepped automation d3 $ volt "1 0.2 0.5 -0.2" # x 3 ``` @@ -47,55 +98,60 @@ d3 $ volt "1 0.2 0.5 -0.2" # x 3 ### ADSR/AR -``` +```haskell --- adsr d4 $ adsr 0 0.2 1 0.2 # x 4 ``` There is also just an `ar` helper too, which has a default D and S value. -``` +```haskell -- create ar d5 $ struct "t f t t" # ar 0 0.5 # x 5 ``` -``` +```haskell -- patternise ar d5 $ struct "t f t t" # ar (range 0.1 1 sine) "<0 0.4>" # x 5 ``` -In the above example, the attack time would grow for each triggered envelope over course of the cycle. +In the above example, the attack time would grow for each triggered envelope +over course of the cycle. ### Sine LFO -This will create an sine waveform, the sine will restart with each cycle, which gives a neat synced/trigger effect for modulations. +This will create an sine waveform, the sine will restart with each cycle, which +gives a neat synced/trigger effect for modulations. -``` +```haskell d6 $ lfo 0.5 # x 6 ``` ### Saw LFO -This will create a sawtooth waveform, the sawtooth will restart with each cycle, which gives a neat synced/trigger effect for modulations. +This will create a sawtooth waveform, the sawtooth will restart with each cycle, +which gives a neat synced/trigger effect for modulations. -``` +```haskell d6 $ saw 0.5 # x 6 ``` ### Clock -``` +```haskell -- clock cv output d6 $ clock # x 6 ``` -`clock` will output a clock cv, which matches the bpm of your tidal project. You can `slow` / `fast` this as well. +`clock` will output a clock cv, which matches the bpm of your tidal project. You +can `slow` / `fast` this as well. ### Amp -Using the `amp` modifier in Tidal Cycles will scale the output of `gate`, `voltage`, `saw`, `ar`, and `lfo`. Awesome for creating more suble modulations. +Using the `amp` modifier in Tidal Cycles will scale the output of `gate`, +`voltage`, `saw`, `ar`, and `lfo`. Awesome for creating more suble modulations. -``` +```haskell d6 $ saw 0.5 # x 6 # amp 0.3 ``` @@ -107,12 +163,16 @@ d6 $ saw 0.5 # x 6 # amp 0.3 Add the `voltage.scd` synths to your active SuperDirt synth definitions. -Evaluate the `voltage.tidal` definitions after starting Tidal. These can also be added to your Tidal startup file. +Evaluate the `voltage.tidal` definitions after starting Tidal. These can also be +added to your Tidal startup file. -In the above examples, `x` maps to a channel on your audio card. If you have an 8 output audio card, the `x` will likely be 0-7. If you are using an aggregate device, please refer to your Audio settings. +In the above examples, `x` maps to a channel on your audio card. If you have an +8 output audio card, the `x` will likely be 0-7. If you are using an aggregate +device, please refer to your Audio settings. --- ### Feedback and/or additions? -If you are actually using this, please join the community here and let me know: https://club.tidalcycles.org/t/using-tidal-to-control-modular-synths-with-cv/863 +If you are actually using this, please join the community here and let me know: +https://club.tidalcycles.org/t/using-tidal-to-control-modular-synths-with-cv/863 diff --git a/voltage.scd b/voltage.scd index 5dccb69..ebfad61 100644 --- a/voltage.scd +++ b/voltage.scd @@ -97,4 +97,16 @@ }).add ); + ( + SynthDef(\nPitch, { + | out, + channel = 0, + freq = 440, + portamento = 0 | + var n = Lag.ar(log2(K2A.ar(freq)/440), portamento); + var sig = LinLin.ar(n, -1, 9, 0, 1); + OffsetOut.ar(channel, [sig]); + }).add + ); + ) From c85360a891dd412ec0c20b463038ca7131ce02ed Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:07:52 +1100 Subject: [PATCH 2/9] readme --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b7ab7c8..2bd094c 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,11 @@ MIDI required! --- -### nDefs +## nDef Defining `nDef` synths provide a constant signal between cycles and -instructions. +instructions. You will need to define a separate `nDef` for each instance you +would like to use. ```c Ndef(\cv_np).source = \nPitch; @@ -38,8 +39,7 @@ Ndef(\cv_np).play(0); ); ``` -You will need to define a separate `nDef` for each instance you would like to -use. +After adding or evaluating the above in SuperCollider, you can use them like: ```haskell -- you can select pitch by number @@ -54,6 +54,8 @@ d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 --- +## Simple + The following synths, while easier to use, create a new cv instance each cycle. This can result in short gaps/breaks in between cycles. You can use `nDef`'s above to remedy this. From 05fb1f67cc627a843bbaee265df15492e984379c Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:09:28 +1100 Subject: [PATCH 3/9] read me --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2bd094c..80b6e66 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ MIDI required! --- -## nDef +### nDef Defining `nDef` synths provide a constant signal between cycles and instructions. You will need to define a separate `nDef` for each instance you @@ -54,7 +54,7 @@ d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 --- -## Simple +### Simple The following synths, while easier to use, create a new cv instance each cycle. This can result in short gaps/breaks in between cycles. You can use `nDef`'s From 9a2fd22e4dae9c1178a82f1b1d2c4e4717843ddc Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:24:59 +1100 Subject: [PATCH 4/9] readme --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 80b6e66..fe3dc5f 100644 --- a/README.md +++ b/README.md @@ -13,23 +13,27 @@ MIDI required! --- -### nDef +### Ndef -Defining `nDef` synths provide a constant signal between cycles and -instructions. You will need to define a separate `nDef` for each instance you +Defining `Ndef` synths provide a constant signal between cycles and +instructions. You will need to define a separate `Ndef` for each instance you would like to use. ```c +// define a unique name for each Ndef Ndef(\cv_np).source = \nPitch; Ndef(\cv_np).play(0); + +// add to dirt library, give it a name that you will use in tidal ~dirt.soundLibrary.addSynth(\cv, (play: { var latency = (~latency ? 0); var freq = ~freq; var channel = ~channel; var portamento = ~portamento; - - Ndef(\cv_np).wakeUp; // make sure the Ndef runs - + + Ndef(\cv_np).wakeUp; + + // schedule the cycles, prevents delayed signals thisThread.clock.sched(latency - 0.025, { Ndef(\cv_np).set(\portamento, portamento); Ndef(\cv_np).set(\channel, channel); @@ -57,7 +61,7 @@ d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 ### Simple The following synths, while easier to use, create a new cv instance each cycle. -This can result in short gaps/breaks in between cycles. You can use `nDef`'s +This can result in short gaps/breaks in between cycles. You can use `Ndef`s above to remedy this. ### Pitch, with octave quantisation From 466054b9ff4f20af0f46013bbe84d06c4c453261 Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:26:56 +1100 Subject: [PATCH 5/9] read me --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fe3dc5f..bf24c2b 100644 --- a/README.md +++ b/README.md @@ -32,15 +32,14 @@ Ndef(\cv_np).play(0); var portamento = ~portamento; Ndef(\cv_np).wakeUp; - + // schedule the cycles, prevents delayed signals thisThread.clock.sched(latency - 0.025, { Ndef(\cv_np).set(\portamento, portamento); Ndef(\cv_np).set(\channel, channel); Ndef(\cv_np).set(\freq, freq); }); -}) -); +})); ``` After adding or evaluating the above in SuperCollider, you can use them like: From 6dc108a5c4760f6298abd87838e69fd551df5dad Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:42:28 +1100 Subject: [PATCH 6/9] gate --- README.md | 45 ++++++++++++++++++++++++++++++++++++--------- voltage.scd | 11 +++++++++++ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index bf24c2b..074fdbc 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,15 @@ Defining `Ndef` synths provide a constant signal between cycles and instructions. You will need to define a separate `Ndef` for each instance you would like to use. +#### Pitch + ```c // define a unique name for each Ndef Ndef(\cv_np).source = \nPitch; Ndef(\cv_np).play(0); // add to dirt library, give it a name that you will use in tidal -~dirt.soundLibrary.addSynth(\cv, (play: { +~dirt.soundLibrary.addSynth(\p, (play: { var latency = (~latency ? 0); var freq = ~freq; var channel = ~channel; @@ -55,6 +57,30 @@ d1 $ n "c3" # s "cv" d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 ``` +#### Gate + +````c +// define a unique name for each Ndef +Ndef(\cv_ng).source = \nGate; +Ndef(\cv_ng).play(0); + +// add to dirt library, give it a name that you will use in tidal +~dirt.soundLibrary.addSynth(\g, (play: { + var latency = (~latency ? 0); + var n = ~n; + var channel = ~channel; + var portamento = ~portamento; + + Ndef(\cv_ng).wakeUp; + + // schedule the cycles, prevents delayed signals + thisThread.clock.sched(latency - 0.025, { + Ndef(\cv_ng).set(\portamento, portamento); + Ndef(\cv_ng).set(\channel, channel); + Ndef(\cv_ng).set(\n, n); + }); +})); + --- ### Simple @@ -63,7 +89,7 @@ The following synths, while easier to use, create a new cv instance each cycle. This can result in short gaps/breaks in between cycles. You can use `Ndef`s above to remedy this. -### Pitch, with octave quantisation +#### Pitch, with octave quantisation ```haskell -- change notes per octave on each cycle @@ -82,7 +108,7 @@ length). d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 1 # glide 12 0.5 ``` -### Gate +#### Gate ```haskell -- sequence gate inputs @@ -92,7 +118,7 @@ d2 $ gate "0 1 0 0 1 1 1" # x 2 `gate` will take a 0/1 pattern and return +5v signals for the `1` values. Use `-1` if you need a -5v. -### Voltage automation +#### Voltage automation ```haskell -- create stepped automation @@ -101,7 +127,7 @@ d3 $ volt "1 0.2 0.5 -0.2" # x 3 `volt` will allow you to sequence voltages however you like. -### ADSR/AR +#### ADSR/AR ```haskell --- adsr @@ -123,7 +149,7 @@ d5 $ struct "t f t t" # ar (range 0.1 1 sine) "<0 0.4>" # x 5 In the above example, the attack time would grow for each triggered envelope over course of the cycle. -### Sine LFO +#### Sine LFO This will create an sine waveform, the sine will restart with each cycle, which gives a neat synced/trigger effect for modulations. @@ -132,7 +158,7 @@ gives a neat synced/trigger effect for modulations. d6 $ lfo 0.5 # x 6 ``` -### Saw LFO +#### Saw LFO This will create a sawtooth waveform, the sawtooth will restart with each cycle, which gives a neat synced/trigger effect for modulations. @@ -141,7 +167,7 @@ which gives a neat synced/trigger effect for modulations. d6 $ saw 0.5 # x 6 ``` -### Clock +#### Clock ```haskell -- clock cv output @@ -151,7 +177,7 @@ d6 $ clock # x 6 `clock` will output a clock cv, which matches the bpm of your tidal project. You can `slow` / `fast` this as well. -### Amp +#### Amp Using the `amp` modifier in Tidal Cycles will scale the output of `gate`, `voltage`, `saw`, `ar`, and `lfo`. Awesome for creating more suble modulations. @@ -181,3 +207,4 @@ device, please refer to your Audio settings. If you are actually using this, please join the community here and let me know: https://club.tidalcycles.org/t/using-tidal-to-control-modular-synths-with-cv/863 +```` diff --git a/voltage.scd b/voltage.scd index ebfad61..a6dbbf2 100644 --- a/voltage.scd +++ b/voltage.scd @@ -109,4 +109,15 @@ }).add ); + ( + SynthDef(\nGate, { + | out, + channel = 0, + n, + portamento = 0 | + var sig = LinLin.ar(n, -1, 9, 0, 1); + OffsetOut.ar(channel, [sig]); + }).add + ); + ) From 4dd6775100a8697f2b6c0f9e36845fdf689bc78f Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:43:06 +1100 Subject: [PATCH 7/9] readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 074fdbc..43e9b27 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Ndef(\cv_ng).play(0); Ndef(\cv_ng).set(\n, n); }); })); +``` --- From 2bb3064d934fc929596992c3df26157a3c21da53 Mon Sep 17 00:00:00 2001 From: mashaal Date: Sat, 11 Feb 2023 23:43:32 +1100 Subject: [PATCH 8/9] readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 43e9b27..c505db6 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 #### Gate -````c +```c // define a unique name for each Ndef Ndef(\cv_ng).source = \nGate; Ndef(\cv_ng).play(0); @@ -208,4 +208,6 @@ device, please refer to your Audio settings. If you are actually using this, please join the community here and let me know: https://club.tidalcycles.org/t/using-tidal-to-control-modular-synths-with-cv/863 -```` + +``` +``` From d8028ebfc92ec9f1249289d4da629f7837013a8c Mon Sep 17 00:00:00 2001 From: Omar Mashaal Date: Sat, 11 Feb 2023 23:56:26 +1100 Subject: [PATCH 9/9] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c505db6..b16f143 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,13 @@ After adding or evaluating the above in SuperCollider, you can use them like: ```haskell -- you can select pitch by number -d1 $ n "20" # s "cv" +d1 $ n "20" # s "p" -- or by note name -d1 $ n "c3" # s "cv" +d1 $ n "c3" # s "p" -- change channel output and/or portamento -d1 $ n "c3 f2" # s "cv" # channel 1 # portamento 0.5 +d1 $ n "c3 f2" # s "p" # channel 1 # portamento 0.5 ``` #### Gate