-- region Lesson 1 -  continuous patterns

-- 'Continuous functions' provide different kinds of waveforms.
-- There's a nice graphic showing sine, square, triangle and sawtooth
-- waves here: https://en.wikipedia.org/wiki/Waveform

-- Here's what the sine waveform sounds like applied to sample playback
-- speed:
d1 $ sound "bd*32" # speed sine

-- and to panning:
d1 $ sound "bd*32" # pan sine

-- and to waveshape distortion (gets loud):
d1 $ sound "bd*32" # shape sine

-- You can manipulate continuous patterns just like other kinds of
-- patterns, for example slowing down:
d1 $ sound "bd*32" # shape (slow 2 sine)

-- The waveforms all move between 0 and 1. So at its lowest point, sine
-- will be 0, and at its highest point it will be 1. Having a value
-- near 0 can be problematic with 'speed', as you can end up with
-- sounds played very slowly that take a long time to complete.

-- To get around this you can add to the sine:
d1 $ sound "bd*32" # speed (sine + 0.5)

-- Or use the 'range' function:
d1 $ sound "bd*32" # speed (range 0.5 1.5 sine)

-- Lets listen to triangle, sawtooth and square waves:
d1 $ sound "bd*32" # speed (range 0.5 1.5 tri)

d1 $ sound "bd*32" # speed (range 0.5 1.5 saw)

d1 $ sound "bd*32" # speed (range 0.5 1.5 square)

-- What happens if you put the continuous pattern on the left?
-- Remember that with '#', the rhythmic structure comes from the
-- left. Try this:
d1 $ speed (range 0.5 1.5 sine) # sound "bd"

-- Silence! Why's that?
-- It's because continuous functions don't actually contain any
-- events. They have values which continually change, without
-- triggering anything.

-- If we want to trigger events in a continuous pattern, we have
-- to explicitly sample values from it. One way to do that is with
-- the 'segment' function:
d1 $ speed (segment 32 $ range 0.5 2.5 sine) # sound "bd"

-- The above samples 32 values per cycle, generating discrete
-- events from them.

-- Another way to do this is with 'binary' or 'boolean' patterns,
-- using the 'struct' function:
d1 $ speed (struct "t(3,8)" $ slow 2 $ range 0.5 2.5 sine)
  # sound "bd"

-- 't' stands for 'true'. So that euclidean rhythm is used to sample
-- events from the continuous sine function. We'll return to
-- binary patterns in another video.

-- You can also add or multiply continous patterns together:
d1 $ sound "bd*32" # speed (range 0.5 2.5 (sine + (slow 2 saw)))

d1 $ sound "bd*32" # speed (range 0.5 2.5 (sine * (slow 2 saw)))

-- I slowed the 'saw' down in the above patterns, so you end
-- up with a sine wave that rises in pitch over two cycles.

-- In Tidal, random functions are also often continous.
-- For example, rand works like sine, saw etc, but returns random
-- values:
d1 $ sound "bd(5,8)" # speed (range 1 3 rand)

-- Perlin is similar, but returns 'perlin noise'. In Tidal, this
-- means that the pattern smoothly transitions between random values,
-- every cycle:
d1 $ sound "bd(5,8)" # speed (range 1 3 perlin)

-- Lets try that with some reverb:
d1 $ sound "bd(7,16)"
   # room 0.7
   # sz (range 0.4 1 $ slow 4 perlin)
-- endregion
-- region Lesson 2 - rand, irand, scramble, shuffle, choose + more
-- Let's start with a look at the 'rand' waveform that we
-- met in the last lesson:

d1 $ n "1*8" # sound "drum"
  # speed (range 1 8 rand)

-- The 'resetCycles' resets the cycle count to '0', as
-- though you'd just started Tidal:
resetCycles

-- If you run resetCycles while the above pattern is running,
-- you'll notice that you also reset the random stream. You
-- will always get the same 'random' numbers every time you
-- start or reset Tidal.

-- You can apply rand to any numerical effect, but might have
-- to adjust the range. For example with the low pass filter
-- that cuts out frequencies higher than the given amount:
d1 $ sound "drum:5(5,8,<0 4>)"
   # lpf (range 200 8000 rand)
   # lpq 0.2

-- 'irand' is similar to 'rand', but creates integers, or
-- whole numbers, from 0 up to (and not including) the given
-- number. This is particularly useful for the 'n' and
-- 'note' controls:

d1 $ sound "rash(5,8)" # n (irand 32)
   # room 0.3 # sz 0.5

-- There are a couple of ways of doing random things in the
-- mininotation too. To randomly choose between subsequences,
-- put a | (vertical bar) between them

-- The second step in this sequence is a randomly pick from
-- four subsequences:
d1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"
   # speed 1.5

-- Also, ? randomly 'drops' an event. In the following the
-- second step has a 50-50 chance of being played.
d1 $ sound "kick clap? kick snare"
  # delay 0.3 # delaytime (1/3) # delayfb 0.8 # speed 1.5

-- (I've added some echo delay to make it sound cool. Delay is the
-- amount of sound to be delayed, delaytime is the length of the
-- echo, delayfb is the feedback of the delay into itself)

-- You can adjust the probability of ? working with a decimal
-- (floating point) number. For example, to have an 80% chance
-- of dropping that clap (and therefore 20% chance of playing
-- it)
d1 $ sound "kick clap?0.8 kick snare"
  # speed 1.5

-- If you apply ? to a subsequence, it'll work individually
-- on each value in the subsequence
d1 $ sound "kick [clap:4 off clap:5]? kick snare"
  # speed 1.5

d1 $ sound "bd*8? clap:4"

-- Ok, onward to functions, starting with scramble. scramble
-- takes a number, which is the number of parts to equally
-- divide a pattern into. It'll then play those parts at
-- random.
d1 $ scramble 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
   # room 0.3 # sz 0.8

-- The above is divided into four parts, and there are
-- eight events in them, so they are played in pairs. This
-- means that 0 is always followed by 1, 2 is always followed
-- by 3, and so on.

-- shuffle takes the same parameters as scramble, and sounds
-- very similar. Can you hear the difference?
d1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
  # room 0.3 # sz 0.8

-- Whereas scramble picks part at random, shuffle plays the
-- parts in random order. The difference is that with shuffle,
-- every cycle, you'll hear each part exactly once. With
-- scramble, there's a (small) chance that you'll hear only
-- one part, played four times.


-- You can maybe hear this better if you play a clap at the
-- same time, to mark the start of the cycle. Then you can
-- hear that parts aren't repeating within the cycle.
d1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
  # room 0.3 # sz 0.8

d2 $ sound "clap"

-- The "choose" function is for when you want to pick between
-- single values. It produces a continuous stream, with no
-- structure, so the following won't produce any events:
d1 $ sound (choose ["bd", "arpy", "snare"])

-- You'll need to provide some structure, with a function like
-- 'segment', which in this case picks 8 values per cycle:
d1 $ sound (segment 8 $ choose ["bd", "arpy", "snare"])

-- Or 'struct', which picks values according to a binary pattern:
d1 $ sound (struct "t t ~ t" $ choose ["bd", "arpy", "kick"])

d1 $ sound (struct "t(5,8)" $ choose ["bd", "arpy", "kick"])

-- Or by combining it with a pattern that *does* have structure:
d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
  # sound (choose ["bd", "arpy", "kick"])

-- Another 'gotcha' - the parameters to choose are a list of values,
-- *not*, patterns, so you can't normally use mininotation there.

-- This *won't* work.
d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
  # sound (choose ["bd*5", "arpy*2", "kick clap"])

-- I'll try to fix this in a future version of tidal! There is a
-- workaround, which is to use the 'innerJoin' function. Then you
-- can choose between patterns:
d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
  # sound (innerJoin $ choose ["bd*5", "arpy*2", "kick clap"])

-- You can use choose with any parameter.

-- For example:
d1 $ sound "clap:4(3,8)"
  # speed (choose [2,5,0.5])

-- The following example is a bit different to the above, because
-- a new value is chosen only once per cycle:
d1 $ sound "clap:4(3,8)"
  # speed "[2|5|0.5]"

-- You could get the same behaviour from choose with 'segment'ing it
-- by a cycle:
d1 $ sound "clap:4(3,8)"
  # speed (segment 1 $ choose [2,5,0.5])

-- The 'wchoose' function is like 'choose', but you can give
-- a 'weighting' for each possibility. So something with a weighting
-- of '4' would be twice as likely to be chosen as one with a weighting
-- of '2', for example:
d1 $ sound "clap*4" # speed (wchoose [(2, 4), (-2, 2)])

-- The above claps will play either with a speed of '2' , or '-2'.
-- You can hear that negative speeds cause sounds to play backwards!
-- '2' has a weighting of '4', and '-2' has a weighting of
-- '2', so is half as likely to play.

-- Here I've weighted things so you get a lot of kicks, occasional
-- claps, and rarer snares:
d1 $ squiz "1 4*8 8*2 0*3"
  # sound (wchoose [("bd", 8), ("snare", 0.5), ("clap", 1)])

-- Ok one more thing! In Tidal, randomness is "deterministic". At
-- a certain cycle time, you will always get the same number. We
-- saw this at the start of the lesson, with resetCycles. That
-- resets the cycle count, as if you just started Tidal up. You
-- can then hear that the 'random' numbers are the same.

-- This can result in unexpected results.
-- Listen to this:
d1 $ sound "clap*2" # speed (range 0.1 2 rand) # pan rand

-- You can hear that on the left speaker, the 'speed' of the
-- sound is always low, and when it pans to the right, it's
-- always high. Strange! This is because the same 'random'
-- number stream is used for both the speed and the pan, so
-- they get the same numbers, and seem to interact.

-- This can be nice! But if you don't want this effect, you can
-- avoid it by manipulating the timeline of one of the random
-- patterns. For example:
d1 $ sound "clap*2" # speed (range 0.1 2 rand)
  # pan (slow 1.001 rand)

-- I only slowed that 'rand' down by a tiny amount, but that's
-- enough to end up with totally different numbers.. So now
-- you're as likely to get lower speeds on the left as on the right.
-- endregion

-- region Lesson 3 - randcat, stripe, degrade, someX, randslice + more

-- randcat

-- randcat is a variant of cat, which we haven't actually looked at
-- yet, so lets start with that..
d1 $ sound (cat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

-- So you can hear that cat 'concatenates' patterns - it plays them
-- one after the other, in order.

-- randcat on the other hand, plays them in random order:
d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

-- You can give it as many patterns to choose from as you like:
d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5",
                     "kick snare:4 . hc(5,8)",
                     "snare:3(9,16)"
                    ]
           )

-- You can use it to randomise control patterns other than sound,
-- e.g. the vowel effect:
d1 $ vowel (randcat ["a e*2 i o", "e o u", "o*8"])
   # sound ("kick snare:4 clap:4")


-- wrandcat is to randcat, what wchoose is to choose. That is,
-- You can give the choices relative probabilities:
d1 $ sound (wrandcat [("bd sn:4(3,8)", 1),
                      ("arpy clap", 0.5),
                      ("cpu(5,8)", 0.25)
                     ]
           )

-- stripe is a weird one. Lets start with a rhythm with the
-- cpu2 samples:
d1 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
  # squiz 2

-- 'fast 2' would squeeze that into two cycles:
d1 $ fast 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
  # squiz 2

-- stripe is similar, but the cycles are random durations,
-- although still fit the cycle:
d1 $ stripe 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
  # squiz 2

-- It sounds random, but against a straight clap, you can hear
-- every other repetition still perfectly aligns with the cycle:
d2 $ sound "clap:4"

-- degrade - remember the ? mininotation modifier in the previous
-- video? It drops events at random:
d1 $ sound "bd*8?"

-- Degrade is a function that does the same:
d1 $ degrade $ sound "bd*8"

-- Just like this:
d1 $ sound "bd*8?0.6"

-- You can specify a probability, by using 'degradeBy'. E.g.,
-- to give each event a 60% chance of being 'lost':
d1 $ degradeBy 0.6 $ sound "bd*8"

-- 'sometimes' applies a function to a pattern, but only sometimes.
-- lets hurry this rhythm, but only sometimes:
d1 $ sometimes (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- Here's the original, which sounds pretty boring in comparison:
d1 $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- You can use it to apply effects as well.
d1 $ sometimes (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- There's also a 'sometimesBy' variant, for specifying a
-- probability:
d1 $ sometimesBy 0.3 (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- There's some aliases for different probabilities:

{-
sometimes = sometimesBy 0.5
often = sometimesBy 0.75
rarely = sometimesBy 0.25
almostNever = sometimesBy 0.1
almostAlways = sometimesBy 0.9
-}

-- So you can do this:
d1 $ rarely (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- somecycles is similar to sometimes, but works on whole
-- cycles at a time, rather than individual events:
d1 $ somecycles (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
  # speed 1.5

-- Again, there's a 'somecyclesBy' variant for being specific
-- about that probability. To apply the squiz, 90% of the time:
d1 $ somecyclesBy 0.9 (# squiz 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
  # speed 1.5

-- randslice is a bit like 'slice' that we met a couple of lessons
-- ago:
d1 $ slice 4 "0 1 2 3" $ sound "break:8"

-- Instead of taking a pattern of slices though, it picks slices at
-- random. So to play a random quarter of this break:
d1 $ randslice 4 $ sound "break:8"

-- We can use 'loopAt' to fit them to a cycle, just like we saw before
-- with 'chop' and 'striate':
d1 $ loopAt 1 $ randslice 4 $ sound "break:8*4"

-- We could also do the same sort of thing by giving 'slice' or 'splice'
-- a random pattern:
d1 $ splice 4 (segment 4 $ irand 4) $ sound "break:8"

-- endregion


-- region  Exercises:
-- TODO Play with delay
# delay 0.3 # delaytime (1/3) # delayfb 0.8 # speed 1.5

-- TODO Play with negative speed, e.g. backward clap


  once $ s "glitch:7" # gain 1.1

  -- d5

d1 $ sound "[bd(5,8), [~ cp]]"
  # speed (range 0.5 4 perlin)
  # gain 0.8


-- Study: "Oh boy! So much fun applying the lessons learned so far."
setcps (75/60/4)

xfadeIn 1 8 $ jux (iter 2) $ loopAt 6 $ chop 1 $ striate 64 $ speed (struct "t(2,7)" $ range 0.7 1 sine) # sound "bev" # gain 0.7 # delay 1 # delaytime 0.675 # delayfb 0.8 # room 0.2

d2 $ juxBy 0 (iter 4) $ rev $ struct "t(5,8)" $ sound "tabla" # n "<21 24> <16 6> <4 12>" # gain 0.8
-- endregion
