-- 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