theHarmonicAlgorithm-3.1.1: Real-time harmonic progression generation for TidalCycles live performance
Safe HaskellNone
LanguageGHC2021

Harmonic.Interface.Tidal.Utils

Description

Shorthand utilities used across live-coding scripts: octave transposition via oct, and time rotation operators pullBy/pushBy that wrap TidalCycles' early/late operators.

Synopsis

Transposition

oct :: Pattern Note -> Pattern ValueMap Source #

Transpose by whole octaves. oct 1 is up an octave, oct (-1) down. The shift is a pattern, so it can move across the cycle: |+ oct "[0 1]*2".

Add onto a pattern:

, cello T (0,1) k vl grid Bass |+ oct (-1)

Time rotation

pullBy :: Pattern Time -> Pattern a -> Pattern a Source #

Rotate a pattern earlier (pullBy) or later (pushBy) in time. Function forms of the TidalCycles <~ and ~> operators, so they compose in a modifier chain rather than needing parentheses. The amount is a pattern, so the rotation can itself vary across the cycle.

, pushBy (1/8) $ harp T (0,1) k vl flow Alto

pushBy :: Pattern Time -> Pattern a -> Pattern a Source #

Rotate a pattern later in time. See pullBy.

Humanisation

humanise :: Double -> Pattern ValueMap Source #

Random per-event velocity jitter, for a less mechanical feel. The argument scales the spread: humanise 1 varies amp by up to ±0.09. The value is centred on ZERO — combine with |+ ("|+ humanise 0.2"), never #, which would replace the amp instead of jittering it.

Onset repair

onset :: Pattern a -> Pattern a Source #

Ensure every event is an onset by aligning whole start with part start, but only at cycle boundaries. Prevents TidalCycles' onset detection from filtering events in cat constructions where inner patterns have period > 1 cycle, without causing MIDI flood from sub-cycle queries.

Note-length constants

hemidemisemiquaver :: Time Source #

Note-length constants, as fractions of a cycle: 1/64, 1/32, 1/16, 1/8, 1/4 and 1/2 respectively. Useful as arguments to pullBy and pushBy, where a named length reads better than a bare fraction.

demisemiquaver :: Time Source #

Note-length constants, as fractions of a cycle: 1/64, 1/32, 1/16, 1/8, 1/4 and 1/2 respectively. Useful as arguments to pullBy and pushBy, where a named length reads better than a bare fraction.

semiquaver :: Time Source #

Note-length constants, as fractions of a cycle: 1/64, 1/32, 1/16, 1/8, 1/4 and 1/2 respectively. Useful as arguments to pullBy and pushBy, where a named length reads better than a bare fraction.

quaver :: Time Source #

Note-length constants, as fractions of a cycle: 1/64, 1/32, 1/16, 1/8, 1/4 and 1/2 respectively. Useful as arguments to pullBy and pushBy, where a named length reads better than a bare fraction.

crotchet :: Time Source #

Note-length constants, as fractions of a cycle: 1/64, 1/32, 1/16, 1/8, 1/4 and 1/2 respectively. Useful as arguments to pullBy and pushBy, where a named length reads better than a bare fraction.

minim :: Time Source #

Note-length constants, as fractions of a cycle: 1/64, 1/32, 1/16, 1/8, 1/4 and 1/2 respectively. Useful as arguments to pullBy and pushBy, where a named length reads better than a bare fraction.

Swing

swing8 :: Pattern Time -> Pattern a -> Pattern a Source #

Swing by musical PROPORTION: 0.5 is straight, 0.667 triplet. Places the swung note at exactly that proportion of its subdivision.

One cycle is one beat here, so swing8 swings eighth-notes (the "&") and swing16 swings sixteenths (the "e"/"a"). Jazz eighth-feel — spang-a-lang, offbeat eighths — takes swing8; a sixteenth shuffle (funk, UK garage, house, phonk, fusion) takes swing16.

f = swing8 0.6

swing16 :: Pattern Time -> Pattern a -> Pattern a Source #

Swing by musical PROPORTION: 0.5 is straight, 0.667 triplet. Places the swung note at exactly that proportion of its subdivision.

One cycle is one beat here, so swing8 swings eighth-notes (the "&") and swing16 swings sixteenths (the "e"/"a"). Jazz eighth-feel — spang-a-lang, offbeat eighths — takes swing8; a sixteenth shuffle (funk, UK garage, house, phonk, fusion) takes swing16.

f = swing8 0.6

Selection

over :: Pattern Double -> [a] -> Pattern a Source #

Step through a list under a 0-1 control signal: the signal's range is divided evenly among the elements, so a knob sweeps through them in order. An empty list is silence.

, over qlink1 [flow, grid, lite]

(-->) :: Pattern Double -> [a] -> Pattern a Source #

Operator form of over.

Random gating

binaryrange :: Pattern Int -> Pattern Int -> Pattern Bool Source #

A boolean gate whose density wanders between two step counts, via binary over a random integer in [lo, hi).

Sidechain

pump :: Pattern Bool -> Pattern Double -> Double -> Pattern Double Source #

A ducking gain envelope — a ghost sidechain. Every onset of the struct pattern drops the gain to 1 - depth, which then recovers to 1 over the release rls. A cycle is a beat here (cps = bpm/60), so rls reads directly in beats: 1 is one beat, 0.25 a quarter of one.

depth is 0 for no duck, 1 to duck to silence, and is a pattern, so it can ride an LFO or the form.

The result is a 'Pattern Double' meant to drive a gain control. It belongs BESIDE the notes as its own element in a stack, never applied to them:

, s1pump "1 0 0 0" 0.6 0.75 # o

Applying it to a note pattern with |*, *| or # splits every note once per overlapping envelope step — a held note re-triggers sixteen times, and drums double-trigger. A hand-written gain pattern coarser than, and aligned to, the note grid (|* vel "0.45 1 0.8 1") is the way to duck note velocities.

An rls longer than the gap to the next onset interleaves two envelopes: the older tail's recovered values arrive after the new duck and cancel it. Nothing clamps this.

Monophony

mono' :: Pattern a -> Pattern a Source #

Monophonic with latest-note priority: each event's whole is truncated at the next onset in the pattern, so a new note always starts on time and stops the one before it — a string being re-fingered, not a queue. Tidal's own mono is the opposite (first-note priority: a later overlapping event is delayed or dropped). Simultaneous onsets keep only the first. Legato scales the truncated whole, so # legato 1 rings exactly to the next note, < 1 leaves a gap, and cranking legato above 1 is unnecessary. Continuous (whole-less) events pass through untouched.

retrig :: Pattern a -> Pattern a Source #

Alias for mono': a new note re-triggers the voice.