SuperCollider Workshop – Code Examples

/*I have been doing  half-day SuperCollider workshops in the past few years. SuperCollider is a code-based audio freeware, and it  is the main program I use for my performance and composition.

Below is my “handouts”  for my workshops. You may copy-past it or download this workshophandouts.txt file and open it with SuperCollider. and you will be able to make some sounds in few minutes.

If you are interested in learning the program, please contact me. */

//

//

//SuperCollider Workshop @ EM2013
//by Joo Won Park (www.joowonpark.net) joowon@joowonpark.net

//SuperCollider is a text-based synthesizer and algorithmic composer.
//SC makes you think in codes and numbers
// Code: “algorithm written in programming language” (from Form & Code by Casey Reas)
// Algorithm: “precise instructions on how to do things” (from Form & Code)
//In other words, SC makes set of instructions to do music/audio related things.

//how to execute things : select/highlight, and then press enter (shift+return), not return
3+6
(3*6)+(2/3)*(4.444432)
10%3
When SC does not understand a line, such as this one, there will be an error message in post window
// when two slash lines are in front of a code, it is considered as comment. execute this line

//Method can be thought as “do something” command. For list of common methods, go to Help->Browse->Common methods.
“Hello”.speak //Mac only
speak(“Hello”)
(3+6).neg
neg(3+6)
(3+6).neg.abs

//SC’s Server needs to be booted in order to execute audio-related codes.
//Boot the Interpreter with command+B or Language->Boot
//Press command+. (period) to stop the sound
{Saw.ar(440,0.5)}.play //Note the syntax.

//use command+D for help files. Double click on the word

//how to use svariables
(
//when executing multiple lines of code, separate them with ;
//grouping codes with () is also very helpful
x=4;
y=8;
x+y
)//you can double click ) or ( to select all the contents inside ()

(x=4; y=8;x+y)
x=4; y=8;x+y

//when using other than a-z as variable, declar it with var
(var words;
words=”double slash at the beginning of the line means comment”;
words.speak
)

(
a={Saw.ar(440)};
a.play
)
//how to make a function {}
//function is a set of instructions that changes value of input x into output y.
//function processes things

//use argument to make an input to the function
y={
arg input;
var distortion;
distortion = input*3;
};
y.value(4);
y.value(20.5);
y.value(5.rand); //execute this code multiple times

(
var appletalk;
appletalk={
arg word;
var talk;
talk = word.speak
};
appletalk.value(“I am an argument”);
)
//note that the following line will not work because argument and var names are local to ()
appletalk.value(“I am out of an argument”)

//this can be fixed using global variables (letters a-z and any var names starting with ~)
z={
arg word;
var talk;
talk = word.speak
};
z.value(“I am an argument”);
z.value(“me too”);

~globalappletalk={
arg word;
var talk;
talk = word.speak
};
~globalappletalk.value(“I am an argument”);
~globalappletalk.value(“me too”);
//one catch with using global var is that you won’t be able to detect syntax (spelling & grammar) errors easily.
~globalappletalkkk.value(“I won’t be executed, but you won’t know why”);

//SynthDef : how to make a function with audio
//use SynthDef (not Synthdef or synthDef) to make an audio-related code with var and arg

SynthDef(“FirstSaw”,{
arg pitch;
var sound,envelope,sound2;
sound = Saw.ar(pitch);
envelope = Line.ar(1,0,2); //make an envelope that changes from 1 to 0 in 2 secondes
sound2 = sound*envelope;
Out.ar(0,sound2)
}).load(s) // make sure to load the synthdef into the server

Synth.new(“FirstSaw”,[\pitch,440]) //make a new synth (an audio event)
Synth(“FirstSaw”,[\pitch,440]) //.new can be omitted
Synth.new(“FirstSaw”,[\pitch,440*2])
Synth.new(“FirstSaw”,[\pitch,69.midicps]) //midi to freq converter

(
var randomizer;
randomizer=60+(12.rand);
Synth.new(“FirstSaw”,[\pitch,randomizer.midicps])
)

//how to change a parameter of a synth in realtime
SynthDef(“LongSaw”,{
arg lforate=3,lfopitch=1,pitch;
var sound,sound2;
sound = SinOsc.ar(lforate,0,lfopitch);
sound2 = Saw.ar(pitch+sound,0.5);
Out.ar(0,sound2)
}).load(s)

a=Synth.new(“LongSaw”,[\pitch,60.midicps,\lforate,1,\lfopitch,10.midicps])
// use .set to change parameters in realtime
a.set(\lforate,3)
a.set(\lforate,5,\lfopitch,10.midicps)
//the following will not work… for now
a.set(\lforate, Line.kr(1,200,0))
a.free //.free deletes the specified synth from the server

//Routine: Making algorithm on how/when to produce sound
//(the bread and butter of sc)
SynthDef(“ForRoutine”,{
arg pitch,vol,dur;
var sound,envelope,sound2;
sound = Saw.ar(pitch);
envelope = Line.ar(1,0,dur);
sound2 = sound*envelope;
Out.ar(0,sound2*vol)
}).load(s)

//here’s a simple randomization of the pitch
Synth.new(“ForRoutine”,[\pitch,60.rand.midicps,\vol,0.5,\dur,2])

//know the difference
2.rand
2.0.rand

//let’s control the range of randomness
(
~randomize=60+(12.rand);
Synth.new(“ForRoutine”,[\pitch,~randomize.midicps,\vol,0.5,\dur,2])
)

//Using a “do loop”, we can repeat the task as fast as the computer can to make a chord
4.do{
~randomize=60+(12.rand);
(“MIDI note “++~randomize++” is chosen”).postln;
//this .postln monitors what note is played
Synth.new(“ForRoutine”,[\pitch,~randomize.midicps,\vol,0.5,\dur,2])
}

//a loop inside a Routine can execute the task with controlled timing

Routine({
4.do{
~randomize=60+(12.rand);
(“MIDI note “++~randomize++” is chosen”).postln;
Synth.new(“ForRoutine”,[\pitch,~randomize.midicps,\vol,0.5,\dur,2]);
1.wait
}
}).play

~sequence1=Routine({
4.do{
~randomize=60+(12.rand);
(“MIDI note “++~randomize++” is chosen”).postln;
Synth.new(“ForRoutine”,[\pitch,~randomize.midicps,\vol,0.5,\dur,0.1+(1.0.rand)]);
0.5.rand.wait
}
})
~sequence1.play
~sequence1.reset //a routine needs to be reset if you want to play the same routine again.

//infinite loop
~sequence2=Routine({
loop{
~randomize=60+(12.rand);
(“MIDI note “++~randomize++” is chosen”).postln; //this .postln monitors what note is played
Synth.new(“ForRoutine”,[\pitch,~randomize.midicps,\vol,0.5.rand,\dur,0.5]);
0.5.rand.wait
}
})
~sequence2.play
~sequence2.stop
~sequence2.reset //a routine needs to be reset if you want to play the same routine again.
//infinite loop2
~sequence3=Routine({
loop{
~randomize=60+(24.rand2);
(“MIDI note “++~randomize++” is chosen”).postln; Synth.new(“ForRoutine2”,[\pitch,~randomize.midicps,\vol,0.5.rand,\dur,0.05]);
0.03.wait
}
})
~sequence3.play
//The above loop will eventually crash the SC in few seconds due to inappropriate memoey allocations (Check Peak CPU of localhost server)
//Use doneAction function in envelopes to prevent it

SynthDef(“ForRoutine2”,{
arg pitch,vol,dur;
var sound,envelope,sound2;
sound = Saw.ar(pitch);
//use doneAction to minimize the CPU usage
envelope = Line.ar(1,0,dur,doneAction:2);
sound2 = sound*envelope;
Out.ar(0,sound2*vol)
}).load(s);

~sequence3=Routine({
loop{
~randomize=60+(24.rand2);
(“MIDI note “++~randomize++” is chosen”).postln;
Synth.new(“ForRoutine2”,[\pitch,~randomize.midicps,\vol,0.5.rand,\dur,0.05]);
0.05.wait
}
})
~sequence3.play

//Arrays : what makes SC a great program
//the bread and butter 2

//array is a list enclosed with []
[0,4,7]
60+[0,4,7]
60+([0,4,7].choose)
Array
SequenceableCollection
Array.series(6,0,2) //whole tone scale

//applying array to make a controlled randomization
SynthDef(“ForRoutine2”,{
arg pitch,vol,dur;
var sound,envelope,sound2;
sound = Saw.ar(pitch);
envelope = XLine.ar(1,0.0001,dur,doneAction:2);
sound2 = sound*envelope;
Out.ar(0,sound2*vol)
}).load(s)

~sequence4=Routine({
loop{
~randomize=60+([0,4,7,11].choose);
(“MIDI note “++~randomize++” is chosen”).postln;
Synth.new(“ForRoutine2”,[\pitch,~randomize.midicps,\vol,0.5.rand,\dur,0.1]);
0.1.wait
}
})
~sequence4.play

//applying array to make a controlled randomization of pitch and rhythm
~sequence5=Routine({
loop{
~randomize=60+([0,4,7,11].choose);
(“MIDI note “++~randomize++” is chosen”).postln; Synth.new(“ForRoutine2”,[\pitch,~randomize.midicps,\vol,[0.5,0.8].choose.rand,\dur,0.1]);
[0.1,0.2,0].choose.wait
}
})
~sequence5.play

//applying array to make a controlled randomization of pitch and rhythm ver2
~pitchset = [0,4,7,11];
~sequence6=Routine({
loop{
~randomize=60+(~pitchset.choose);
(“MIDI note “++~randomize++” is chosen”).postln; Synth.new(“ForRoutine2”,[\pitch,~randomize.midicps,\vol,[0.5,0.8].choose.rand,\dur,0.1]);
[0.1,0.2,0].choose.wait
}
});
~sequence6.play

//change ~pitchset to to play different harmony
~pitchset=[0,3,7,11];
~pitchset=Array.series(6,0,2);
~pitchset=3 //this will give you an error
// Also, synth.set will not work, or will work for only one note because each note triggered with Routine is a separate synth
~pitchset=[3] //make an array with one list instead

//play a melody loop
~pitchset = [0,4,7,11];
~pitchlist = ~pitchset.asList; //convert an array into a “list” that can be interpreted by do loops
~sequence7=Routine({
loop{
~pitchset.do{
arg chosenpitch; //the first argument in a do loop corresponds to the firt value on the list
~randomize=60+chosenpitch;
(“MIDI note “++~randomize++” is chosen”).postln; //this .postln monitors what note is played
Synth.new(“ForRoutine2”,[\pitch,~randomize.midicps,\vol,0.5,\dur,0.1]);
0.1.wait;
}
}
});
~sequence7.play
~pitchset=[0,4,7,11]-2
~pitchset=Array.series(25,0,2)

//Challenge : analyze the following code. run ~sequence7 first
Routine({loop{~pitchset=[[0,4,7,11],[0,4,7,11]-2,[0,4,7,11]-4].choose;4.wait}}).play
//Summary : why use SC?
//SuperCollider makes users explore different modes of expression and composition
//1. customization & precision not easily available to commercial DAW
{SinOsc.ar(Line.kr(0,22000,20.39203),0,0.3)}.play
//2. “If computers could be used to model what we know, then perhaps we could also use them to simulate what we don’t know” (Form+Code by Reas)
//If computers could be used to model what we can play, then perhaps we could also use them to simulate what we can’t play
//3. Powerful DSP

//vanilla
SynthDef(“PulseThing”,{
arg pitch=500,width=0.5, vol=0.8; //you can set initial value of arguments
var sound1;
sound1 = Pulse.ar(pitch,width,vol);
Out.ar(0,sound1)
}).load(s);
Synth(“PulseThing”);

//vanilla + one topping
SynthDef(“PulseThing”,{
arg pitch=500,width=0.5, vol=0.8;
var sound1;
sound1 = Pulse.ar([pitch,pitch*0.5],[width,width*0.5],vol); //array makes a new signal
Out.ar(0,sound1)
}).load(s);
Synth(“PulseThing”);

//vanilla + many toppings
SynthDef(“PulseThing”,{
arg pitch=500,width=0.5, vol=0.8;
var sound1,cluster,mix;

cluster= Array.fill(10,{0.3.rand}).postln; //fill an array with five radom values between 0 and 0.3
sound1 = Pulse.ar(pitch+(pitch*cluster),width*cluster,vol); //this will create a 10 channel audio
mix = Mix(sound1); //mix 10 channel audio into a mono signal

Out.ar(0,mix)
}).load(s);
Synth(“PulseThing”); //note that you need to run the SynthDef again to make a new set of randomized array

//mint
SynthDef(“PulseThing”,{
arg pitch=500,width=0.5, vol=0.8;
var sound1,cluster,mix,filter;

cluster= Array.fill(10,{0.3.rand});
sound1 = Pulse.ar(pitch+(pitch*cluster),width*cluster,vol);
mix = Mix(sound1);

filter = HPF.ar(mix, MouseX.kr(300,10000));
//highpass filter controlled with x-axis of a mouse

Out.ar(0,filter)
}).load(s);
Synth(“PulseThing”);

//Challenge: here’s the above SynthDef in one line.
{HPF.ar(Mix(Pulse.ar(500+(500*(Array.fill(10,{0.3.rand}))),0.5*(Array.fill(10,{0.3.rand})),0.8)), MouseX.kr(300,10000))}.play
//banana split
SynthDef(“Voice”,{
arg pitch=500,width=0.5;
var voice,sound1,cluster,mix,delay;

cluster= Array.fill(10,{0.3.rand2});
voice = AudioIn.ar(1); //get real-time audio
sound1 = PitchShift.ar(voice,0.2,1+cluster); //this will create a 10 channel audio
mix = Mix(sound1*0.3); //mix 10 channel audio into a mono signal
delay = CombC.ar(mix,0.5,0.4,2);

Out.ar(0,delay+voice)
}).load(s);
Synth(“Voice”);

//sundae
~sample1 = Buffer.read(s,”sounds/Fflies.aif”); //load a sample to a buffer
//SC willtry to find the sound in the folder where the actual SC application is located
SynthDef(“Voice”,{
var voice,sound1,cluster,mix,delay;

cluster= Array.fill(10,{0.5.rand2}); //fill an array with five radom values between -0.3 and 0.3

sound1 = PlayBuf.ar(2,~sample1.bufnum,1+cluster); //this will create a 20 channel audio using a sample
mix = Mix(sound1*0.3); //mix 10 channel audio into a mono signal

Out.ar(0,mix)
}).load(s);
//press record button in localhost server to record a sound
Synth(“Voice”);

//Examples:
www.100strangesounds.com

//Final SC Tips
//- count your ()s and {}s. one missing ( can trigger a dramatic whining in the post window
//- spelling is crucial. Synth and synth are different. Have a habit of naming your variable with lower-case letters so it it does not get syntax-colorized with blue.
//- be extra careful in spelling when using a gloabal variable
//- SC documentation is a great textbook.
//For further studies, I recommend to look at the following features
if
In
Out
MIDIResponder
OSCresponder
GUI
Patterns

 

 

Joo Won’s First Recital in Ohio

FacultyRecital

 

If you are in NE Ohio area,  come to my debut concert at the Oberlin Conservatory. Performance is my best way to say hello to the community.  The concert is free and open to public. I do not know many people around here yet, so please share this information to your Ohio friends who are into experimental/noise/electroacoustic sounds. Or invite your worst enemy.

Updates – Aug 2014

About a month ago, I have moved from Philadelphia, PA to Oberlin OH. I got a new job as a Visiting Assistant Professor of Technology in Music and Related Arts (aka TIMARA) at the Oberlin Conservatory of Music. I am extremely happy about this opportunity,  and am ready to meet great students and artists.

map

Oberlin is quite a different place than my former job at the Community College of Philadelphia. I worked at a metropolitan community college for six years, meeting a diverse group of students in a vocation-oriented curriculum. I strongly recommend CCP if you are in the Philadelphia area and wants to learn about recording and production. My current job, on the other hand, is in a private liberal arts college in a relatively small city, and I am expected to teach yet another group of diverse students who are studying in a music conservatory environment. They also seem to have  a different goal and aesthetics (compare the works of my CCP students and those of TIMARA).  It is thus inevitable that I need to create a different teaching plan.

Below is the link to my new syllabi for Fall 2014. I am teaching courses that I have not taught in my previous works, but my experience gained at Philadelphia is thoroughly integrated in the new syllabi. For example, two+ years of directing an electronic ensemble at the Community College of Philadelphia taught me how to plan a 16-week long improvisation ensemble class for any kinds of instrumentation. A SuperCollider class I taught at the Temple University became a basis for the Algorithmic Composition class that I’ll be teaching for an upper-level TIMARA students.

This year is going to be an exciting year for my life as a teacher. Like the past few years, encounters with brilliant minds and hearts will give me a chance to grow. I hope to do the same for my students.

Lastly, if you are around the NE Ohio area, please come to my first Oberlin concert on  9/10/14 at 8PM. The show is free and open to public.

How much I made with 100 Strange Sounds? $15.38

100 Strange Sounds is my recent electronic music project. It consists of 100 videos of live original music on YouTube. I worked on the project for 1.5 years, producing 5 hours of music using computer, found objects, and consumer electronics. I worked on the Strange Sounds harder than any other projected I have done, and it gave me a chance to grow artistically. It also produced the income from advertisement:

15.38

I am satisfied with the number of views, but the total estimated earnings of $15.38 is a laughable number. I made more money at working 3 hours in my first job that required sitting down in a room for few hours.  Here’s what $15.38 income taught me about video streaming monetization.

ProjectPeriod

After becoming a YouTube Partner, I started to allow YouTube to monetize my video when I started 100 Strange Sounds project. To monetize means that I allow YouTube to show an advertisement in my uploads, either as a fullscreen or as a little box in the video. Whenever the viewer sees or clicks an ad on my video, I have a possible earning from the ad. My first 100 Strange Sounds video was uploaded in mid December of 2012, but I did not make earnings from the ad until June of 2013 (see above chart provided by YouTube Analytics).

This is because allowing ads on the video does not automatically pay the channel owner. It seems that Youtube/Google needed to verify that  I am a real person and have been uploading legal contents. The verification process took longer time than I expected.  I received a snail mail (not email) from Google to finalize the process after 6 months of monetizing my first  video.

I do not know where my ad earning of December 2012 to May 2013 went, but I decided to forget it for now.  For a better understanding of my earnings calculation, here is another version of the graph that shows the period when my videos started to earn ad money for me.

MoneyMakingPeriod

You may estimate that my earnings per view would be $15.38/34094=0.04¢, but it is not. There are some 100 Strange Sounds videos that I decided not to monetize. More specifically, I have not monetized videos that feature my family or friends for moral reasons. Also, many views are not counted towards monetization if YouTube decides that the viewers did not see the ad.  If I see only the views that are counted for monetization, which is about 10% of the total view, I can calculate that the earnings per view is about $15.38/3533=0.4¢ or $0.004.

monetizedPlaybacks

I also noticed that the videos with most earnings are not necessary the one with most playbacks. For example, Strange Sounds #42 has 170 monetized playbacks, but it creates less earning than Strange Sounds #47 with 121 monetized playbacks. My wild guess is that No 47 is one of the only videos that mentions a specific toy in a specific brand, but I have no evidences.

To10EarnigVideos

The last thing I learned about online streaming earning is that my Google Adsense account has payment threshold of $100. In other words, Google will not cut me a check if I earn less than $100. With 0.4¢ per view, I still need about 21500 more valid views to reach the threshold. If I continue to get about 3500 valid views per year , I’ll get my first payment in about 6 years.

To summarize, here are the financial lessons I learned from 100 Strange Sounds:

  1. Earnings per view is 0.4¢ only if the view is counted as monetized playback
  2. The Adsense account for the Youtube needs to be completely set to get earnings. It took me almost 6 months since the first monetized video to complete the process.
  3. I get paid in chunks of $100. With 0.4¢/view, 25000 monetized views are needed to see the payment in my bank account.

Despite all these financial discouragement, I don’t regret about uploading my works at YouTube. There are far worse services that will put an ad on your video without your permission and will not even consider giving you a share of the ad earnings (more on this story later). I will continue to monetize my 100 Strange Sounds videos for study purposes. I am planning to take some economics courses in the near future, and I am hoping that my personal hard-earned financial data could be useful in some research.

PS: If you liked reading this article or any works I do, please support by watching my video from my YouTube playlist

Making Your Life as an Artist

Making Your Life As an Artist by Andrew Simonet is a free, concise book that can be downloaded at the Artists U site. It took me less than three hours to finish the book, but it gave me great tips and advices on how to live a balanced and sustainable life as a musician.

MakingLastPG

The author is an active choreographer, but the principles discussed in the book can be applied to music (or any other art). I was stressed for not having enough time and space to work  in the past week. After reading this book, I learned good strategies on how to plan, finance, make time, and focus on artistic mission. I’m not so stressed anymore.

The first three chapters discusses about the role of artists in the world, why artist have challenging life, and the skills that artists already have to overcome such challenges. The last five chapters provide practical examples and how-to’s on making a living as an artist. I was also enlightened to read about entertainment vs art, science vs art, career vs mission, perfect vs good enough, and other analyses. I particularly love the analogies and examples:

“[Seed savers and some farmers] grow things that don’t fit with industrial agriculture. They preserve the seeds for plants we may need someday. This is what artists do culturally.” -p29

“Art is not cultural broccoli, something you hate but should consume.” – p33

“A lot of artists’ lives are built for 23-year-old single, frenetic, healthy, childless workaholics. That doesn’t last. Our lives change and our needs change” – p77 

For its price and quality of information, the book has great value for my artist friends. It has even greater value for my non-artist friends since it will help you understand their art/music/dance friends a little better. I am planning to use the book as a reading material for my improvisation ensemble and upper-level music classes. I look forward to have a great discussion with the students about artist sustainability.

 PS: For my musician friends and students who are starting their post-college music career, I also recommend Beyond Talent by Angela Myles Beeching. 

PSS: Since I mentioned about art and dance, here’s a little clip on my  collaboration with a dancer friend.