Category Archives: Research

Armor+2 – for clarinet and computer


Required Software and Hardware

  1. Bb clarinet and Bass clarinet : A solo player will switch the instruments during the piece.
  2. Computer : a Macintosh with OS 10.9+ is preferred, but PC should also work.
  3. SuperCollider : this is a free software that runs the computer part.  Download it from HERE if SuperCollider is not installed already
  4. Armor+2.scd file : this is the computer part for the piece. If you don’t have it already, download it from the composer’s website (Here) or contact the composer at https://www.facebook.com/joowonmusic
  5. One Microphone: Close-mic the clarinet. A good condenser microphones is preferred.
  6. Audio Interface: The interface should have at least one microphone inputs and three outputs. The first two outputs send computer part. The third output sends a click track.
  7. Headphone: connect the click track output to the headphone for the performer.
  8. Speakers/PA : Connect the stereo output of the audio interface to the sound reinforcement system.

How to Use Armor+2.scd File

  1. Make sure that your audio interface is set as the default input and output device for the computer.
  2. Open Armor+2.scd in SuperCollider.
  3. Go to Menu-> Language-> Evaluate File.
  4. You will hear measure 1 in few seconds. Press command+period(.) or go to Menu-> Language-> Stop  to stop.
  5. Repeat steps 3-4 to restart.
  6. Do not let the computer go to sleep mode. It may cause a disconnection between the hardware and software.

Performance Instructions

  1. The electronic part should be as loud as the acoustic part. Adjust the gain and/or microphone position accordingly. Most of the computer parts are live-processed or algorithmic. The computer part processes the sound of the ensemble in realtime, and it will sound slightly different in each performance.  It is important to follow the tempo as accurately as possible to be in sync with the computer part.  The click track is not absolutely necessary, but it may assist the performance. The performer should be able to operate the computer part as the computer part requires runs automatically after the first measure.
  2. The click track starts at measure 1 without a count off. Place the bass clarinet near the performance space for a quick switch at measure 68.
  3. The following boxed words notated in the computer part indicate an addition or variation of the computer part: AM, AM2, and FM add harmonic elements. Ticks are short percussive sounds. Stutter imitates a short segment of the performer’s sound. Reverb simulates a room sound. Pad is a long synthesized tone, which can have a smooth or sharp beginning.
  4. There are some extra files in the download site. If the performer wants to practice the piece by sections, use the files in ForPractice folder. Armor+2-ClickOnLeft.scd has the click track on the left channel. If the performer does not want to operate SuperCollider part during the practice, he/she can use the recorded electronics part in ForTapeVersion folder.

Snake Extension – What I have learned in the Spring semester

I taught Digital Signal Processing Theory class in the last Spring. I have never studied this hard to teach a course. As a result, I learned (or relearned) about DSP quite a bit. More specifically, I learned to appreciate elegance of “classic” techniques, such as AM, FM, sample-and-hold, and delays. I think I can explain them in digital terms. Most importantly, I learned that digital signal processing is all about (good) math.

The best way to wrap up the semester and summarize what I have learned is to make a piece using the new techniques I have learned.

1. To start the piece, I begin with a sinusoid generated with very slow Low Frequency Oscillator (LFO) on its pitch. The LFO’s shape is made with a  wave shaping function using polynomials. The result is an unusual curve pitch pattern.

2. On this polynomial curve, I add sample and hold. The smooth line gets “steps” in terms of pitch. I change the S&H rate to create different rhythms

3. As the piece progresses, I would like to have some frequency modulation gradually fading in.

4. This should sound fun if I have more of them. Here is an example of all the techniques with four sinusoids. The rate of S&H, the shape of polynomial curve, and the modulation rate of FM are randomly selected for each line.

The resulting sound sounded like a good accompaniment for a noisy electronic piece. So I played a no-input mixer and custom synthesizer over the polynomial pads. I also continued the piece with algorithmically drum part that I have developed for Snake and Ox track in my latest album (more about this track later).

Here’s the final result, Snake Extension. I think I’ll add this to my solo repertoire.

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