Blog 9

Below are snippets of all the sounds I’ve developed so far. These are skeletal at the moment and will be refined and played with in the actual performance with all the interesting features and functions that I’ve learned along the way. Worth note – the forest biome doesn’t have any real sound yet because I keep faffing around with samples and I can’t quite find anything I like.

The sounds are generally all based off of the same pattern with some changes in samples and other variables such as speed and up. The cave sound has its own score, with the plains score playing faintly in the background. This was because the cave has a different atmosphere to the rest of the game, it’s kind of oppressive and spooky.

Blog 8

This week I was fortunate enough to attend a talk given by Alex McLean for DefShef – a group for functional programming enthusiasts – on the 9th of Feburary. Whilst the talk was intended to address the implementation of Tidal in Haskell, Alex instead focused mainly on features of Tidal and their uses, as well as giving a demonstration.

For me, this talk clarified certain features of Tidal which I wasn’t 100% clear on, such as the difference in use between squared brackets and curly braces in pattern creation (squared ensuring that multiple patterns’ elements all occur within a fixed time (polymetric) and curly allowing multiple patterns to have different timing (subdivided)).

I’ve created a simple graph (below) to represent the differences between the two.

time

This talk also made me aware of features of Tidal which I wasn’t aware of, either due to them being new developments or because I had not found any documentation for them. One example of this is the crossfade feature, which is included in the newest release of Tidal.

Alex also discussed the every, often, sometimes and rarely modifiers, which can be used to add effects to your expression at different intervals. I was previously aware of the “every” keyword, but didn’t realise there was a range of similar keywords to use.

Provided Alex is not busy on the performance day, he said he may attend.

Blog 7

For my final official week studying Tidal, I’ll be looking at a few more functions  and seeing what I can put together using what I’ve learned. My concern at the moment is trying to make my loops less, well, loopy.

First off, degrade is a function which I find really interesting. It randomly removes events from a pattern about 50% of the time which has the effect of making the music less samey. I found it worked really well applied to the melody in last weeks live-code example.

Degrade can be used on individual elements of a pattern rather than the entire pattern by adding a ? after each element that you want to have the potential to degrade.

Pick is a function which takes a pattern of sounds and a pattern of folder indexes and on each cycle chooses a number from the list of indexes and plays each sound in the pattern using the assigned index.

e.g. d1 $ sound (pick <$> “bd sn can*3 cp” <*> slow 2 “0 1 2 3 4”) will pick a number (n) between 0 and 4, then proceed to play “bd:n sn:n can:n*3 cp:n”. This process is repeated on each cycle.

within can be used to apply a function to only part of a pattern and takes in a start point an an end point as a decimal. For example, feeding in 0.75 and 1 will lead the effect to be applied to the last 25% of the pattern.

Using these new features and some of the ones I’ve learnt along the way through practice and experimentation, I’ve come up with this.

d1 $ density 1.5 $ stack [
append'(every 4 (|*|up “2”) $ sound $ slow 2 $ (fit 3 [“arpy”, “arpy:5”, “arpy:3”, “arpy:1”, “casio”] “0 [~ 1] 2 1”))
(every 2 rev $ sound $ (fit 3 [“arpy:1”, “arpy:4”, “arpy:6”, “arpy:3”, “arpy:2”] “0 [~ 1] 2? 1”))|+|shape “1” |+|gain “0.5”,
sound (brak $ (pick <$> “[jvbass [jvbass jvbass]] jvbass” <*> “0 1 3”)),
sound (brak “[sn[sn sn]] sn”) |+|gain “0.75”,
every 4 rev $ within (0, 0.5) (|+|shape “1”) $ sound (pick <$> “bd sn can*3 sn” <*> slow 2 “0 1 2 3 4”) |+|vowel “a” |+|gain “0.75”,
degrade $ sound “[casio casio:1] casio:3?” |+|gain “0.75”
]

It ended up being a nice sounding little track and I feel like I now know enough of the features of Tidal to go forth and try to make game music. I need a little more practice so I can improve my update speed, as I’m still relatively slow with some of the newer or more structurally complex features and the code I put together for game music will only be a skeleton of what it’ll hopefully become in the performance.

 

Blog 6

This week I learned of the stack function, which can layer multiple patterns into one. I applied this to the second sound sample from last week’s blog, which was made up of 3 samples.

d1 $ stack [
sound “[sn[sn sn]] sn” |+|shape sinewave,
every 4 rev $ (sound “bd:2 sn:3*2 cp jvbass”),
foldEvery [2, 4] (|+|up “3”) $ sound (samples’ “arpy” (irand 8))
]

It’s a much more concise way of layering the patterns when you don’t need to be able to have individual control over their playback. Speaking of which, individual samples can be stopped by using their identifier and silence together. E.g. d1 silence.

Stack also allows modifiers to be applied to all of the samples at once, rather than having to add them individually to d1, d2,..dn.

Density is used to compress a pattern so that it plays a given number of times in one cycle. Density 2 would make the pattern play at twice the speed.

Brak is an interesting effect as it adds a short pause on each second cycle of a pattern and then compresses the first two elements. It’s described as sounding like a breakbeat, but even after some googling I’m not entirely sure what that is.

Finally, anticipateIn is a function which can be used for scheduling. You pass in the number of loops you want to pass by before the pattern changes, and what you want the pattern to change to, and the rest is handled for you. Alternatively, anticipate exists which is the same kind of thing but defaults at 8 cycles.

I’ve used these new features to try to improve the second example track from last week. Soundcloud link and source code are below.

(N.B. anticipate seemed to layer the d1 pattern for reasons I’m not entirely sure of so it doesn’t sound as good as it should)

d1 $ stack [
sound (brak “[sn[sn sn]] sn”) |+|shape sinewave,
every 4 rev $ (density 2 $ sound “bd:2 sn:3*2 cp jvbass”) |+|gain “0.75”,
foldEvery [2, 4] (|+|up “3”) $ sound (samples’ “arpy” (irand 12))
]

t1 (anticipateIn 16) $ foldEvery [2, 4] (|+|up “3”) $ sound (samples’ “arpy” (irand 12))

 

Blog 5

This week I thought it would be good to post up some examples and experimentation with what I’ve learned so far up to and including this week.

This first pattern shows an amalgamation of things I’ve learned over the last 4 weeks (not everything, but a decent sounding example of some). The source code is included below.

d1 $ append'(sound (samples’ “arpy” (irand 6))) (every 2 rev $ sound (samples’ “arpy” (run 8)))
|+|shape rand
|+| speed “[1 2 -2]/3”
|+|vowel “a e i o u”
|+|crush “2 2*2 3 3”

This week I looked at run and irand, which are included in the pattern above. run takes an integer and iterates through that many samples in the selected folder, starting from 0. irand takes an integer and returns a random number between 0 and i-1, which is used to index a random sample from the selected sound folder.

The second pattern is another attempt at shoehorning in the other things I’ve learned so far, but using multiple layers of audio.

d1 $ sound “[sn[sn sn]] sn”
|+|shape sinewave
d2 $ every 4 rev $ (sound “bd:2 sn:3*2 cp jvbass”)
d3 $ foldEvery [2, 4] (|+|up “3”) $ sound (samples’ “arpy” (irand 4))

Blog 4

This week I studied “Compositions” in Tidal, which are basically functions which deal with multiple patterns. They may be useful as a layering technique when it comes to composing game music.
Append and append’ are functions which combine two patterns into one. The difference between the two is that one occurs on a single cycle and one occurs over two cycles. The effect of append is that it shortens each pattern so that they can both fit within a single cycle.

d1 $ append (sound “piano:3*2 piano 5”) (sound “glocken:4 glocken:8”)

d1 $ append’ (sound “piano:3*2 piano 5”) (sound “glocken:4 glocken:8”)

I also looked at the cat functions of which there are 3. They work in a similar way to append, except they can be used with more than two patterns.

cat, like append, condenses all the patterns into a single cycle. The example below gives the same output as the append example. Additional patterns can be added with comma separation.

d1 $ cat [sound “piano:3*2 piano 5, sound “glocken:4 glocken:8”]

slowcat, like append’, maintains the original pattern duration when concatenating the patterns, meaning the number of cycles it takes to complete the new pattern is equivalent to the number of patterns concatenated. The example below has the same output as append’.

d1 $ slowcat [sound “piano:3*2 piano 5, sound “glocken:4 glocken:8”]

The final cat function is randcat, which is similar to slowcat with the exception that it plays the given patterns in a random order rather than cycling through them from first to last.

The final function I studied was one which I feel will be very useful for maintaining the flow of game music. That function is interlace. It takes two patterns and blends them into a new pattern, which would probably be good for transitioning between different modules.

d1 $ interlace (sound  “piano:3*2 piano 5”) (every 4 rev $ sound  “glocken:4 glocken:8*2”)

To achieve the interlacing it uses distortion and so careful control is needed to achieve the desired effect.

Blog 3

Chapter 8 of Happy Learn Haskell taught me that if-else statements do exist within Haskell, they are just pretty useless when compared to the other (better) ways of achieving that kind of functionality. I guess that’s why it wasn’t mentioned in Learn You A Haskell last week.

I am beginning to notice that there is little crossover between Haskell as a programming language and Tidal as a programming language, except in the case of errors which I now know are often due to incorrect pattern matching. From this point forward I will discontinue the study of Haskell unless I reach a point in Tidal where I feel it is necessary to continue with Haskell.

On the plus side, this will give me more time with Tidal.


My Tidal studies this week have taught me 4 new modifiers.

slow takes a number greater than 1 and slows the pattern by that many times. Interestingly, it can also take a number between 0-1 to speed a pattern up.

d1 $ slow 2 $ sound “bd sn”

up changes the playback speed to effectively increase the pitch. It conforms to a 12 tone (or 8 note) scale. The below example would play the first sound in the marimba folder, but at a speed which increases its pitch by 3 semitones.

d1 $ sound “marimba” #up “3”

crush is a parameter that alters bit depth between 1 and 16. 16 is the original bit depth and 1 plays nothing. Its applications are probably fairly restricted to adding fuzzy distortion.

d1 $ sound “glocken” |+|crush “5”

gain acts as a volume control. If given a number less than 1, it decreases the volume of the sound, and values greater than one increase the volume. 1 acts as the baseline.

d1 $ sound “arpy” |+|gain “2”

Blog 2

This week I studied Chapters 3 and 4 of Learn You A Haskell For Great Good which covered typeclasses and pattern matching.

Functions in Haskell have types, and it is good practice to declare the function type on non-basic functions. Function declaration details the types of all inputs and the output that the outcome is mapped to.

In the example below, the function takes in two integers and outputs another integer.

multiplyTwo :: Int -> Int -> Int

multiplyTwo x y = x * y

Typeclasses work as an interface for types, where if the type is part of a typeclass it supports the behaviours defined within the typeclass. There are some predefined typeclasses detailed within the chapter which won’t all be detailed here, but interesting to me were the Show and Read typeclasses.

Types which are members of the Show typeclass can have their data presented as a string when the show function is called upon them, and types which are members of the Read typeclass can be converted from a string to another type which is a member of the Read typeclass dependent on context. The author of Learn You a Haskell gives a great example of this which I’ve shown below.

blog2lyah

In the second example, Haskell cannot infer the output type of “4” because it doesn’t have context in the same way as the previous examples, which call for the manipulation of the input allowing type to be inferred.

In order to get around this, output type can be supplied at the function call.

read “4” :: Int

This example would return 4.

Patterns work in a similar way to switch cases in that a provided parameter will fall through each case until it finds a match. It is good practice to make the list of cases exhaustive, or adding a default case such as in other programming languages. It is best to define more specific patterns towards the top of the list and more general ones towards the bottom to prevent the specific case from being caught by a generalised condition.

Pattern matching can also be used with tuples and list comprehensions.

Guards are similar in concept to patterns, but are used to determine whether some value is true or false, and work similarly to if statements. Rather than specifically matching a value as you might with a pattern, guards return based on truth. A list of guards works similarly to a series of else-if statements and have an “otherwise” case similar to an else.

There also exist Where and Let bindings. Where bindings can be used after functions to bind an expression to a name and then work using the expression. These definitions are only visible to the function itself. Let bindings are set out like let <bindings> in <expression> and can be used to introduce an expression into functions and introduce new variables in a local scope.

Finally this week for Haskell are case expressions. These work very similarly to patterns and are useful for pattern matching in the middle of an expression.

And that’s all there is to it.


 

For Tidal this week, I looked at a few modifying functions.

|*|vowel adds an effect which distorts the sound in an interesting way. It’s difficult to describe, but it makes the sound sound like a vowel. Imagine the sound passing through your mouth when you’re holding your mouth an the a, e, i, o or u shape and you’re there. The “u” vowel is particularly interesting because it has the effect of making the sound muffled, as though you are hearing it from underwater.

foldEvery works similarly to every, however it allows you to specify more exact parameters. Every 2 would add a modification every 2 times the program looped, but suppose you wanted to add a vowel on every 2nd and 5th loop?

d1 $ foldEvery [2,5] (|+| vowel “a”) $ sound (samples’ “piano” (“0 5 3”))

This is possible to do with every by chaining multiple everys together, but this is just nicer for when you want to apply the same pattern to multiple loops.

d1 $ every 2 (|+|vowel “a”) $ every 5 (|+|vowel “a”) $ sound (samples’ “piano” (“0 5 3”))

As you may be able to tell, I’ve also learned the use of the samples’ function which negates the need for manual assignment. The above code plays sounds 0, 5 and 3 from the piano folder. This could also be achieved with manual assignment.

d1 $ every 2 (|+|vowel “a”) $ every 5 (|+|vowel “a”) $ sound “piano piano:5 piano:3”

 

Blog 1

This week I tried to acquaint myself with the basic theory of Haskell, which is my first experience with functional programming.

In functional programming, functions accept arguments and return an answer based off of the original argument. Arguments are not modified within the function and variables stay the same.

Haskell is described as lazy – no data is shown until it is absolutely necessary to do so, for example when a function has finished calculating a result. It is also statically-typed (that is to say, Haskell is aware of variable types at compile-time) and uses type inference where type is not explicitly stated.

When writing Haskell functions, the programmer does not need to worry about adding a control flow structure in the same way as they may have to with procedural languages. An example of this is given below. To my understanding, the C# factorial function executes a multiplication function x + 1 times (with a 0-starting for loop) and store to a variable after each iteration whereas Haskell will perform the entire calculation at once.

cshaskell

As well as this, I learned some useful information about comprehension and use of functions.

Infix functions in Haskell are functions whose calls can be embedded between parameters. Suppose the divide function were to be called with an aim of dividing 90 by 10. This can be done in one of two ways – div 90 10 or 90 `div` 10. This is to allow easier comprehension of functions where functions may be complex.

‘ may be used at the end of a function name to denote a strict version of the function or a slightly modified version of a function, which is a naming convention I was not previously aware of.

List comprehensions in Haskell are fairly compact and consist of an output function before a pipe and a predicate after the pipe. There may also be conditions after the predicate.

[ x | x <- [1..100], x `mod` 5 == 0]

In this example, the output function returns x. The input set is a list of all numbers between 1-100 with x drawn from the list. The predicate is that returned numbers will only be those who are divisible by 5 with no remainder (or who return 0 when modulus 5 is called on them)

Tuples are a data structure commonly found in Haskell. In my mind, they work quite similarly to vectors. Each element must have a set size and corresponding variables within elements must be of the same data type. For example [[1 , 2], [3, 4, 5], [5, 6]] is a valid list but [(1 , 2), (3, 4, 5), (5, 6)] is an invalid tuple, and [(1, “One”), (1, “Two”)] is valid, where [(1, 1), (2, “Two”)] is not. Functions do exist to create tuples from lists, but only if they meet the conditions for a valid tuple.


Also this week I looked at some entries of the 365 Tidal Patterns blog. I found that many of them won’t compile which I initially thought may be due to sample names, but it seems to be syntactic errors which at this point I’m unsure of how to fix.

Because of this I had to use patterns at random instead of following my initial plan.

This week, through playing around with these patterns I learned several things.

|+|speed controls playback speed of individual arguments in sound. In the example below, the playback speed of hh and cp would change to 2 and 3 respectively. This can be a way of altering pitch.

d1 $ sound “bd hh cp”

|+|speed “1 2 3”

|+|shape alters the distortion (and volume) of the block using a value between 0 and 1 (the default is 0). This can be used with different wave patterns already defined in Tidal, such as sinewave.

The “every” keyword is used to instruct the program to do something every x number of times. This works quite effectively with the rev keyword, which reverses the order of the samples, to make the music sound less repetitive.

d1 $ every 2 rev sound “bd sn:1 sn:2”

This example also shows how the colon is used to select a particular sample from the named sample folder. The numbering system is 0-indexed so the use of sn:1 will take the second sample in the sn folder.

A First Look at Impromptu

After admiring the work of Andrew Sorensen, I decided to check out Impromptu.

Impromptu is a live-coding environment suited for audio and visual performance. It’s OSX only and, unlike ChucK, works with asynchronus timing. The Impromptu website shows pseudocode for both.

Synchronus:
play-note(now)
time = (now) + 44100
play-note(now)

Asynchronus:
play-note(now)
play-note(now + 44100)

I have to say, the omission of a time variable is a nice one. Time variables can also be used with asychronus timing, but usually only where you need absolute precision.

Whilst Impromptu has some extremely good tutorials and documentation, I unfortunately found it to work only sporadically. I believe it was an issue with evaluating expressions and the audio chain, probably caused by inexperience.

Overall, I found Impromptu much more intuitive than ChucK, and I feel as though I achieved more (in spite of having some issues). Because of this, I’ll probably have a look at Extempore which is a more recent cross-platform environment built off of Impromptu.

Sig