#######################################################################

# Live coding for beginners - making music with FoxDot

#######################################################################

# Written by Ryan Kirkbride & adapted for this workshop by Lucy Cheesman

#######################################################################

# Basics

######################################################################bytearray

# Before you can get started in FoxDot, you need to launch SuperCollider, and type in the following line of code: 

FoxDot.start

# Then run that code in SuperCollider by pressing Ctrl+Enter on Windows or Cmd+Enter on Mac

# To "run" code in FoxDot, put your text cursor on the line of code and press Ctrl+Enter on Windows or Cmd+Enter on Mac.

# Let's start by making a drum beat!
# d1 is the name we give to the player, and "play" tells FoxDot we want to use some samples


d1 >> play("x-o-")


# Anything you type between the speech marks will play a different sound

d1 >> play("Site Gallery")

# Try changing what it says! What does your name sound like?

# You can stop it using 'stop'

d1.stop()


# Let's try adding some synth sounds too
# To add a new player we just have to call it something different

p1 >> pads()

# p1 is the new name we've chosen, and 'pads' is the name of the synth in FoxDot.  
# There's a lot of synths to choose from - if you run the code below you'll see a list (watch out though, loop, play1 and play2 are something different!)

print(SynthDefs)


p1 >> varsaw()

# Try changing the name of the synth and see if you can find one you like

# ok let's stop those - Clock.clear() stops everything

Clock.clear()

# Let's add some notes to our player

p1 >> pads([0,2,4])

# If we use round brackets instead of square, it plays the notes together

p1 >> pads((0,2,4))

# Or we can use a combination:

p1 >> pads([0,1,2,(3,5,7)])

# Putting a list inside of another list alternates which value is used

p1 >> pads([0,2,[4,7]])

# Try adding your own numbers and experiment with the brackets to see how it sounds!

# Press Ctrl+. to quickly stop everything

#######################################################################

# Keywords

#######################################################################


# After we set the pitch, we use "keywords" to assign other instructions - like durations

p1 >> pads([0,1,2,3], dur=1)

p1 >> pads([0,1,2,3], dur=1/2)

p1.stop()

# What happens when we use lists for pitch and durations that are not equal size?

p1 >> pads([0,1,2,3], dur=[1,1/2,1/2])

# Useful keywords are "amp", "dur", "sus", "pan", "oct"

p1 >> pads([0,1,2,3], dur=[1,1/2,1/2], amp=[1.5,0.5], sus=2, pan=[-1,1], oct=[5,5,5,(4,6)])

# Try changing some of the numbers or adding your own - can you figure out what's going on?

# Ok - lets stop that.

p1.stop()

#######################################################################

# Rhythms

#######################################################################

# We can make our drum pattern more complex by using brackets

# The square bracket plays multiple samples in the space of one step:

d1 >> play("x-o[--]")

d1 >> play("x-o[---]")

d1 >> play("x-o[-------]")

d1.stop()

# The round brackets alternates the sound used:

d1 >> play("x-o(-o)")

d1 >> play("x-o(-[-o])")

d1 >> play("x-o(-[-(-o)])")

d1.stop()

# And the curly braces selects a sample at random for more variety

d1 >> play("x-o{-o}")

d1 >> play("x-o{-[--]o}")

# You can stop it using stop!

d1.stop()

# Just like before we can use keyword arguments:

d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1])

# You can also change the rate the audio is played 

d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=1)

d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=2)

d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=0.5)

d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=-1)

d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=[1,2,0.5,-1])

d1.stop()

# We can use cut to slice our samples down (this can be useful if we're using long samples and we don't want them to overlap):
    
d1 >> play("1V2V")


d1 >> play("1V2V", cut=0.5)


print(Effects)

# To play things at the same time, just use multiple Players. 

p1 >> pads([0,2,4,9,7], dur=1/4)

d1 >> play("x-x-")

d2 >> play("  * ")

# To stop everything, press "Cmd+." or run the line of code below.

Clock.clear()


#######################################################################

# Adding and sequencing effects

#######################################################################

# We can also add effects to the players 


l1 >> blip(dur=4)


l1 >> blip(dur=4, echo=0.5)


l1.stop()

# Could you hear the difference? Below are some other effects to try out.

# High Pass Filter - only lets frequencies *above* this value into the signal

d1 >> play("x-o-")

d1 >> play("x-o-", hpf=500)

d1 >> play("x-o-", hpf=5000)

d1 >> play("x-o-", hpf=[0,100,250,500,1000,2000,4000,8000])

d1.stop()

# Low pass filter - only lets frequences *below* this value into the signal

d1 >> play("x-o-")

d1 >> play("x-o-", lpf=5000)

d1 >> play("x-o-", lpf=500)

d1 >> play("x-o-", lpf=[50,100,200,400,800,1600,3200,6400])

d1.stop()

# Chop - chops the signal into "n" parts

p1 >> pluck([0,4], dur=4, chop=4)

p1 >> pluck([0,4], dur=4, chop=8)

p1 >> pluck([0,4], dur=4, chop=320)

p1.stop()

We can also chop a sample:
    
d1 >> play("1 2 ")

d1 >> play("1 2 ", chop=8)

d1.stop()

# -- Sustain is how long a note is held for
# -- What happens when you use a different sustain than duration?

p1 >> pluck([0,4], dur=[3/4,3/4,1/2], chop=4)

p1 >> pluck([0,4], dur=[3/4,3/4,1/2], chop=4, sus=2)

p1.stop()

# Shape - wave shape distortion

b1 >> bass(dur=4, shape=0)

b1 >> bass(dur=4, shape=0.5)

b1 >> bass(dur=4, shape=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0])

# -- Try combining different effects in the same player (room and mix and reverb):
    
b1 >> bass(dur=4, shape=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0], chop=16, room=0.5, mix=0.2)


# Try changing the values and adding your own effects

# Remember you can stop a player by using the name of the player and .stop()

b1.stop()

# Or you can stop everything using Ctrl+. or Clock.clear()

Clock.clear()

#######################################################################

# Let's make a tune!

#######################################################################

# All of the timing is handled by "Clock" and we can change the tempo if we want

Clock.bpm = 144

# Let's make a basic tune

# 1. We can start with a simple drum beat

d1 >> play("x ")

# 2. Add a bassline

b1 >> sawbass([0,-1,3], dur=[4,4,8])

# 3. Let's add some chords - we can make sure they fit with the bass by setting the pitch relative
# to the pitch of the bass, b1, using the + sign).

p1 >> star(b1.pitch)

p1 >> star(b1.pitch + (0,2,4))

p1 >> star(b1.pitch + (0,2,4), dur=[3/4, 3/4, 1/2])

# 4. Create you own melody to go with it - pitch a SynthDef

print(SynthDefs) # e.g. blip

# e.g. p2 >> blip([0,7,6,4,2], dur=1/2, sus=1)

p2 >> blip([0,7,6,4,2], dur=1/2, sus=1)

# 5. Let's add to our drums. Try making this more complex by using the different brackets

d1 >> play("x-")

d2 >> play("  * ")

# What happens to our chords if we change the bass?

b1 >> sawbass([2,3,4,6], dur=4)


# Challenge time! Use "room", "chop", "hpf", "lpf", and "shape" in the tune we
# worked on to customise your sound and add your own bit of flair.

# Feel free to copy and paste from the examples if you're not sure of the syntax
# You can always change some parameters
# Or if you're feeling brave just go for it!


# Press Cmd+. to stop playing or

Clock.clear()