tidal-voltage/README.md

247 lines
5.7 KiB
Markdown
Raw Permalink Normal View History

2022-03-02 00:28:45 +00:00
<img src="https://cdn.sanity.io/images/os5aqg3v/production/1df428507bbab5a032dcb43701e80b4e9aeb29f5-2048x1475.jpg?auto=format" width="500" />
2022-02-21 05:55:46 +00:00
2024-05-05 14:10:42 +01:00
# Tidal Voltage
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
A small set of SuperDirt synths and Tidal helpers to control modular synths. No
MIDI required!
2020-05-20 11:02:06 +01:00
2023-01-11 11:41:35 +00:00
**2023 updates:**
2023-02-11 12:05:21 +00:00
- nDef synths
2023-01-11 11:41:35 +00:00
- Added `saw`, `lfo` triggered LFOs
- `amp` now controls the scale of `gate`, `voltage`, `saw`, `ar`, and `lfo`
---
2023-02-11 12:09:28 +00:00
### Simple
2023-02-11 12:07:52 +00:00
2023-09-24 11:44:26 +01:00
The following synths, while easy to use, create a new CV instance each cycle.
2023-02-11 12:24:59 +00:00
This can result in short gaps/breaks in between cycles. You can use `Ndef`s
2023-09-24 11:44:26 +01:00
(below) above to remedy this.
Easy install, 1st step: Put voltage.scd into your
[SuperDirt/synths](https://github.com/musikinformatik/SuperDirt/tree/develop/synths)
library.
2nd step: Evaluate `voltage.tidal` (or add to your `bootTidal.hs` config)
2023-02-11 12:05:21 +00:00
2023-02-11 12:42:28 +00:00
#### Pitch, with octave quantisation
2023-02-11 12:05:21 +00:00
```haskell
2020-05-20 11:02:06 +01:00
-- change notes per octave on each cycle
2023-01-11 11:41:35 +00:00
d1 $ pitch "0 10 8 1" # octave "<12 31 8>" # x 1
2020-05-20 11:02:06 +01:00
```
2023-02-11 12:05:21 +00:00
`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...
2021-01-03 12:38:54 +00:00
2023-02-11 12:05:21 +00:00
`glide` accepts a strengh (in semitones, relative to scale), a rate (in step
length).
2020-08-23 01:06:23 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2021-01-03 12:40:08 +00:00
-- glide to pitch
2023-01-11 11:41:35 +00:00
d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 1 # glide 12 0.5
2020-08-23 01:06:23 +01:00
```
2023-02-11 12:42:28 +00:00
#### Gate
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2020-08-23 01:06:23 +01:00
-- sequence gate inputs
2023-01-11 11:41:35 +00:00
d2 $ gate "0 1 0 0 1 1 1" # x 2
2020-05-20 11:02:06 +01:00
```
2023-02-11 12:05:21 +00:00
`gate` will take a 0/1 pattern and return +5v signals for the `1` values. Use
`-1` if you need a -5v.
2020-05-20 11:02:06 +01:00
2023-02-11 12:42:28 +00:00
#### Voltage automation
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2020-05-20 11:02:06 +01:00
-- create stepped automation
2023-01-11 11:41:35 +00:00
d3 $ volt "1 0.2 0.5 -0.2" # x 3
2020-05-20 11:02:06 +01:00
```
2020-08-23 01:06:23 +01:00
`volt` will allow you to sequence voltages however you like.
2020-05-20 11:02:06 +01:00
2023-02-11 12:42:28 +00:00
#### ADSR/AR
2023-01-11 11:41:35 +00:00
2023-02-11 12:05:21 +00:00
```haskell
2023-01-11 11:41:35 +00:00
--- 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.
2020-05-23 11:46:56 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2021-01-03 12:38:26 +00:00
-- create ar
2023-01-11 11:41:35 +00:00
d5 $ struct "t f t t" # ar 0 0.5 # x 5
```
2023-02-11 12:05:21 +00:00
```haskell
2023-01-11 11:41:35 +00:00
-- patternise ar
d5 $ struct "t f t t" # ar (range 0.1 1 sine) "<0 0.4>" # x 5
```
2023-02-11 12:05:21 +00:00
In the above example, the attack time would grow for each triggered envelope
over course of the cycle.
2023-01-11 11:41:35 +00:00
2023-02-11 12:42:28 +00:00
#### Sine LFO
2023-01-11 11:41:35 +00:00
2023-02-11 12:05:21 +00:00
This will create an sine waveform, the sine will restart with each cycle, which
gives a neat synced/trigger effect for modulations.
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2023-01-11 11:41:35 +00:00
d6 $ lfo 0.5 # x 6
2020-05-20 11:02:06 +01:00
```
2023-02-11 12:42:28 +00:00
#### Saw LFO
2023-01-11 11:41:35 +00:00
2023-02-11 12:05:21 +00:00
This will create a sawtooth waveform, the sawtooth will restart with each cycle,
which gives a neat synced/trigger effect for modulations.
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2023-01-11 11:41:35 +00:00
d6 $ saw 0.5 # x 6
```
2020-05-20 11:02:06 +01:00
2023-02-11 12:42:28 +00:00
#### Clock
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
```haskell
2020-05-20 11:02:06 +01:00
-- clock cv output
2023-01-11 11:41:35 +00:00
d6 $ clock # x 6
2020-05-20 11:02:06 +01:00
```
2023-02-11 12:05:21 +00:00
`clock` will output a clock cv, which matches the bpm of your tidal project. You
can `slow` / `fast` this as well.
2020-05-20 11:02:06 +01:00
2023-02-11 12:42:28 +00:00
#### Amp
2023-01-11 11:41:35 +00:00
2023-02-11 12:05:21 +00:00
Using the `amp` modifier in Tidal Cycles will scale the output of `gate`,
`voltage`, `saw`, `ar`, and `lfo`. Awesome for creating more suble modulations.
2023-01-11 11:41:35 +00:00
2023-02-11 12:05:21 +00:00
```haskell
2023-01-11 11:41:35 +00:00
d6 $ saw 0.5 # x 6 # amp 0.3
```
2020-05-20 11:02:06 +01:00
---
2023-09-24 11:44:26 +01:00
### Expert
If you run into issues with gaps or clicks in the synth defs above, you can
choose to use nDefs, which allow more consistent CV usage.
These need to be defined in your start up file.
### 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
(
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
);
// 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
(
SynthDef(\nGate, {
| out,
channel = 0,
n,
portamento = 0 |
var sig = LinLin.ar(n, -1, 9, 0, 1);
OffsetOut.ar(channel, [sig]);
}).add
);
// 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);
});
}));
```
---
### Fine print
2020-05-20 11:02:06 +01:00
**These require a DC-coupled sound card.**
Add the `voltage.scd` synths to your active SuperDirt synth definitions.
2023-02-11 12:05:21 +00:00
Evaluate the `voltage.tidal` definitions after starting Tidal. These can also be
added to your Tidal startup file.
2020-05-20 11:02:06 +01:00
2023-02-11 12:05:21 +00:00
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.
2020-08-23 01:21:37 +01:00
---
### Feedback and/or additions?
2023-02-11 12:05:21 +00:00
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