diff --git a/README.md b/README.md index 842b9eb..b16f143 100644 --- a/README.md +++ b/README.md @@ -2,100 +2,188 @@ # 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` --- -### Pitch, with octave quantisation +### Ndef +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(\p, (play: { + var latency = (~latency ? 0); + var freq = ~freq; + var channel = ~channel; + 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: + +```haskell +-- you can select pitch by number +d1 $ n "20" # s "p" + +-- or by note name +d1 $ n "c3" # s "p" + +-- change channel output and/or portamento +d1 $ n "c3 f2" # s "p" # 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 + +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 +#### 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 +#### Voltage automation -``` +```haskell -- create stepped automation 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 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 +#### 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 +#### 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 +#### 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 +#### 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 +195,19 @@ 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..a6dbbf2 100644 --- a/voltage.scd +++ b/voltage.scd @@ -97,4 +97,27 @@ }).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 + ); + + ( + SynthDef(\nGate, { + | out, + channel = 0, + n, + portamento = 0 | + var sig = LinLin.ar(n, -1, 9, 0, 1); + OffsetOut.ar(channel, [sig]); + }).add + ); + )