Tuesday, October 9, 2012

Csound Mini-Lesson 3: Kicks in Csound

Kicks are the heartbeat in music. A wonderful pulse that gives music liveliness. In electronic dance music, it is the most important aspect of a track.

There is more than one way to make a kick synthetically. I'm going to show you the way I make my kicks.

By the end of this tutorial, you'll be able to make kicks that sound like this:



So, let's get started!

PART 1: the "boom"

The first part of our kick will be what I call the "boom" of the kick. This is the main part of our kick. To make this, we will start of by putting a 60hz sine wave through an exponential envelope:

gisine ftgen 0, 0, 4096, 10, 1
instr 1   
kenv expseg 1, .6, 0.0001
a1 oscil .9*kenv, 60, gisine
outs a1, a1
endin

This is known in the industry as an "808" kick (though I highly doubt this is how it actually was done on a tr-808.) Useful for layering, but there isn't enough body for a main kick. What I do is create a line which goes from a little over 60hz to a little bit under 60hz. If done very quickly (under 500ms), this can be perceived as a percussive sound:

gisine ftgen 0, 0, 4096, 10, 1
instr 1   
kdrop linseg 120, .2, 40
kenv expseg 1, .6, 0.0001
a1 oscil .9, kdrop, gisine
outs a1*kenv, a1*kenv
endin

This sounds a lot better! If your music is a sparse, this might be a good stopping point. If not, you may need to add a some click. You may also notice that instead of applying the amp envelope at the oscil opcode, I applied right at the output. Since all we are doing is scaling a signals frequency, both places work!

PART 2: the "click"

Another aspect of a kick is it's click. This high frequency content will define the attack of the instrument. To make this, we will take a white noise generator and put it through a very fast envelope. I played around a little bit with balance and changed some routing:

gisine ftgen 0, 0, 4096, 10, 1
instr 1   
kdrop linseg 120, .2, 40
kenv expseg 1, .6, 0.0001
arand rand .05
kclik linseg 1, 0.004, 1, 0, 0
a1 oscil .9, kdrop, gisine
aOut = (a1 + (arand*kclik))*kenv
outs aOut, aOut
endin

Here is a line-by-line play of our final kick, bottom to top:

"endin": the instrument end tag.

"outs aOut, aOut": send the audio signal aOut to our left and right speakers.

"aOut = (a1 + (arand*kclik))*kenv": Mixing our click and boom together. Order of operations matter here. (arand*kclik) is our click. we are taking our white noise and multiplying it by our fast envelope. a1 is our boom. We are combining our boom and click together and then multiplying that by one envelope. This makes it sound more unified.

"a1 oscil .9, kdrop, gisine": Our oscillator creating our "boom." Amplitude of 9, linear envelope modulating pitch, f-table referencing sine.

"kclik linseg 1, 0.004, 1, 0, 0": This is our very fast envelope (4ms) that will make our click.

"arand rand .05": white noise generator.

"kenv expseg 1, .6, 0.0001": exponential envelope which will shape the amplitude of our kick.

"kdrop linseg 120, .2, 40":  linear envelope which quickly jumps from 120 to 40 hz.

"instr 1": instrument begins. it has an ID of 1

"gisine ftgen 0, 0, 4096, 10, 1": our generated sine wave in an f-table. has a global i-rate variable called "gisine."




And there you have it!

Monday, October 1, 2012

Envelopes, Noise, and "Snares"


 Tutorial 2: Making simple EDM snares.

If your song has a beat, your song is going to have a snare. Why not try to make one yourself? Lets make some ridiculously simple snare sounds in Csound!

The concept of our synthesized snare is quite simple: take a noise source and put it through an envelope with a fast transient. You can do this on just about any synthesizer. With Csound, you can get a little bit more specific what the noise source is and what kind of envelope it is. For this example, we will be showing two different sounding envelopes and noise sources, with a total of 4 combinations.

Envelopes: Linear vs. Exponential

Envelopes are huge, especially when you are dealing with times that are smaller than half a second. An envelope with an attack time of 10ms is going to have completely different character than that of of a sound with an attack time of 100ms.

Even more drastic than the time it takes to move from point to point is how it moves to that point. In Csound, envelopes can either be linear or exponential.

A linear envelope for our snare could look like this:

    aenv linseg 1, .2, 0

The opcode called linseg is producing an envelope that linearly goes from 1 to 0 in .2 seconds. The output of this opcode is going to the audio-rate variable aenv.

An exponential envelope for our snare could look like this:

    aenv expseg 1, .2, 0.0001

The opcode called expseg is producing an envelope that exponentially goes from 1 to 0.0001 in .2 seconds. Note that 0 can’t be used in an exponential curve.

Csound’s white noise generator:
    Csound has many random number opcodes. One of these opcodes can produce random numbers at an audio rate and produce white noise:

    anoise rand .8

The opcode called rand is creating random numbers between the values .8 and -.8 to anoise. If we send anoise to our speakers, we will get white noise at 80% full scale (assuming 0dbfs=1.)

Using FM aliasing as a noise source:
    We can create very unusual sounding aliasing sounds with an FM oscillator with an absurdly high modulation index. The result is noise. But it is meaningful noise:
    gisine ftgen 1, 0, 4096, 10, 1
    afm foscil .5, 100, 1, 1, 100000, gisine
Instead of wasting space explaining what each opcode does, I suggest you check out the entry in the Csound Manual. It is a resource should never be without when working in a language as vast as Csound. Learning how to read from this manual will help you learn Csound on your own. If you are lost on what exactly a carrier or modulator or modulation index is, you can read up about it here.

It’s quite simple to put the sound and the envelope together in an orchestra file:

instr 1
iamp = p4
a1 rand iamp
aenv expseg 1, p3, 0.001
outs a1*aenv, a1*aenv
endin

This produces a pretty common snare patch. You’ll notice I’ve made the amplitude and length parameter values so I can control them from the score like this:

i1 0 .4 .6

The duration is .4 seconds and the amplitude is 60%. Play around with duration and see how the exponential envelop shapes the sound.

Offline vs. Realtime rendering:

Csound was originally intended for offline rendering, as computers at the time had the computing power of a 10 calculator you’d buy at CVS. You’d write your Csound patch run it, and come back the next day to hear what it sounded like. Offline rendering is very useful for generating samples that you can then import into a DAW. Simply running csound from the commandline with no flags will give you a file called test.wav (or test.aif on a mac):

csound filename.csd

You can specify the output file you want with -o

csound -osnare.aif filename.csd

If you are on a Mac, files will be rendered as an AIFF file regardless of extension (unless you specify the kind of audio file you want.) Conversly, PC and Linux files will render to wav files, regardless of the extension they have on it.

For the sake of brevity, I have put the rest of today’s files onto github. You can download the file here. You’ll find 4 separate instruments, each utilizing a different envelope and noise source.

Next week, we will be building a supersaw lead sound in Csound.







https://github.com/zebproj/csdfiles/blob/master/snare.csd

Friday, September 21, 2012

Tutorial 1: The CSD structure, and beating frequencies



Today, we will make some beats with Csound. 

Text editors and/or frontends for Csound will not be discussed much, but they are required to run Csound. I personally write up everything in VIM, and then use Csound from the command line. Much information is available on the various tools you can use. Go explore. Don't worry, my examples should work. 

Csound has two main sections. The orchestra is the section that makes the sound, and the score is the section that tells the orchestra what to play.  These two sections used to be two separate files (eg: song.orc and song.sco) back in the day, but now they consolidated into one file with an extension of *.csd. 

A CSD is an XML file. Open up a new file and type this:

<CsoundSynthesizer>
<CsOptions>
</CsOptions>
<CsInstruments>
</CsInstruments>
<CsScore>
</CsScore>
</CsoundSynthesizer>


To break it down:

1. everything is in encapsulated between <CsoundSynthesizer> and </CsoundSynthesizer>
2. everything between <CsOptions> and </CsOptions> will set command line flags.
3. everything between <CsInstruments> and </CsInstruments> will hold the orchestra
4. everything between <CsScore> and </CsScore> will hold the score.


The first thing we will do is make a header inside the <CsInstruments> tags:

<CsInstruments>
sr = 44100
ksmps = 1
nchnls = 2
0dbfs = 1
</CsInstruments>

Basically, we are telling Csound that we want a project with:
a sample rate 44.1khz (sr), 
a control rate which matches the sample rate (ksmps), 
stereo audio (nchnls),
and range of loudness where 0 is no sound, and 1 is full-scale digital audio (maximum loudness). 

There's no real need to know exactly what these things do right now. Just know that we will be using this almost all the time in every example we have.

We will now make an instrument which produces a simple sine wave, right below the header we made. Do not copy and paste. Type it:

<CsInstruments>
sr = 44100
ksmps = 1
nchnls = 2
0dbfs = 1

gisine ftgen 0, 0, 4096, 10, 1
instr 1
a1 oscil .4, 100, gisine
outs a1, a1
endin
</CsInstruments>

Here is (basically) what is happening, line by line:
1. a variable called "gisine" which makes a sine wave. this is outside of the instrument.
2. the instrument starts. it has an instrument ID of 1.
3. oscillator module using the oscil opcode. It has an amplitude of .4, and a frequency of 100. it is reading the sine wave from the variable "gisine." the audio information is being sent to a variable called "a1."
4.  We send the audio from the oscillator (a1) to the stereo speakers.

Now that we made the instrument, we need to instruct Csound to play it. In the <CsScore> section of our CSD file, add this:
<CsScore>
i1 0 4
</CsScore>

This is our score. As I said in the last post, it is only a text table. Each value is called a parameter value, or p-value:
p1 ("i1") tells us that we want instrument 1 to play a note.
p2 ("0") tells us that we want to play a note right when we compile (0 seconds after performance starts).
p3 ("4") tells us that we want to hold the note for 4 seconds. 

If you are going to run Csound from the commandline, you need to tell Csound to play the file in realtime and not render it to an audio file. Add this to the <CsOptions> section:

<CsOptions>
-odac
</CsOptions>

Now run it!

If you got a sinewave, good. If not, check the terminal output and see if there are any error messages. Typos and syntax errors are very common. 

Supposing that we want to control pitch from the score. We can use this by adding additional parameters and p-values. We can modify our instrument like so:

gisine ftgen 0, 0, 4096, 10, 1
instr 1
a1 oscil .2, p4, gisine
outs a1, a1
endin

We can now declare the frequency of our oscillator in the p4 slot in our score:

i1 0 4 100

Does it have to be 100hz? nope. It can be 101, 200, 1000, 20000, 1.41760hz, or any numerical value. Lets have a little bit of fun by making some "beats" by using this as your score:
<CsScore>
i1 0 4 300
i1 0 4 301
</CsScore>
Two or more simultaneous tones with similar frequencies will clash with one another. Here we have a 300hz sine and a 301hz sine. The farther apart they are, the faster they get. Try changing 301hz to 305hz.

Harmonic beats, though simple, can be kind of fun. Try running this as your score:

<CsScore>
i1 0 16 300
i1 0 4 305
i1 4 4 308
i1 8 2 310
i1 10 2 308
i1 12 4 305
</CsScore>


Figure out what each line is doing. What is their frequency? When do they start? how long do they stay on? Try making your own scores from sine waves. Remember that things get louder when you start adding sine waves together. Turn the volume down and be careful with your ears!


Thursday, September 20, 2012

What is Csound, why it sucks and why it rocks

I'm going to try to make a few mini-lessons here on Csound. We'll see how this goes.

I'm assuming that you have never used Csound before, so I'll start from the beginning. 

Csound can be thought of as a text-based modular synthesizer. Synthesizers are "built" inside of a text editor using modules called opcodes. Modules include various kinds of oscillators, filters, LFOs, and envelopes, but there are more unique opcodes for things like physical modeling, granular synthesis, additive resynthesis, and phase vocoding. There are ways to implement programming idioms, but Csound is not a programming language. This is a tool for musicians and musically-minded individuals, not a way for programmers to incorporate musical elements into their work. 

I learned about Csound 4 years ago, and have been using it quite intensely the past year and a half. It is one of my most used programs for synthesis and sound design. 



To start things off, I'd like to give four reasons why Csound sucks and is a terrible program to use:

1. It's old. The source code is an accumulation of over 20 years of work. It can be very difficult to incorporate Csound seamlessly with modern tools in a DAW. It has quirky old-timey conventions.

2. The score. It's a terribly old-fashioned text table with timings and other information which Csound will use to play instruments. Writing out note-sequences can be very time-consuming, and can be done much quicker in a DAW. 

3. The orchestra. It's basically the section of a Csound synthesizer where you build the synthesizer. It's only text, so it can be very hard to read at times. It's very hard to come up with sounds quickly in Csound, since they are typed out and not "patched" or "twiddled."

4. Everyone in the Csound community makes strange music that's hard to listen to. It's rare that you find a (good) Csound composition with a beat, something in 4/4 time, or even something with western tonality! To me, the stereotypical Csound composition is droney, with shrill blips and scary clusters of notes. 


Conversely, I also would like to give four reasons why Csound rocks and is an incredible tool for electronic music:

1. It's old. Not only that, but the community is very fervent on backwards compatibility. Csound compositions written twenty years ago can still run flawlessly on the most recent version of Csound. In the electronic music world, it is very typical to have to learn new software every 5 years or so, and to essentially lose any projects made with the older software (backwards compatibility is not a guarantee.) You take the time to Learn Csound, and your projects will be timeless.

2. The score. it's only a text file. One can very easily generate scores for your instruments in any programming language with file I/O (which is basically every modern programming language.) Your scores are not bound by the constrictions found in a MIDI sequencer. I'll get more into this later, but things like audio-precise timing and floating point resolution parameters. 

3. The orchestra. It forces you to think at a very low level for sound design. Working with Csound, you will gain expert knowledge on how to make engaging and unique sounds with synthesizers. As an added bonus, this can be applied to any available commercial synthesizer. 

4. Everyone in the Csound community makes strange music that's hard to listen to. And that's a good thing. There is so much easy music out there. Hard music is food for your brain. As a musician, it's the hard music that makes you grow. 

Tuesday, April 10, 2012

A month of Generation

I've always loved the idea of generative computer music. I appreciate it with the same kind of wonder that I do with trees. They both start out a tiny little acorn which you plant in the ground. You give it time and it grows, twisting and turning in beautiful ways that you'd never expect.

I really want to get a firmer grasp on composing generative music, so I will try to write one very short piece of generative music a week for 4 weeks. Finals and such are totally going to muck this up. I can already tell...


Anyways, here is my Week 1 composition. This one basically utilizes the fibonacci series to determine what notes to play.  There are a total of three voices, each being played by a simple 1:1 FM instrument with linear decay.




Composition is looped based, so the same algorithm is used more than once within the piece.

Friday, January 27, 2012

Blender and Csound

Allow me to show you a video I made a few days ago:
What you probably saw was a nine second video of a 3d computer animation of a purple cube striking a gold platform of sorts. If you had your speakers on, you would have also noticed a ringing sound happening every time the cube touched the platform.
The video itself is pretty lame and boring, but the idea behind is actually something I've been thinking about doing for a while.
What is happening
The video above has two separately created components: a video track and an audio track. The audio track was rendered using Csound, reading instructions on what notes to play from a something called a score file. This same set of instructions was read and interpreted by another piece of software called Blender, which then produced the visual part you saw above.

The steps
While there is probably a much more efficient way of going about this, this is the process I used to produce this animation. My computer programming knowledge is pretty sparse, so I go with what I know will work.
1. Write/Generate a Csound Score. (In this case, the score was generated with information regarding instrument number, start time, duration, pitch, and amplitude)
2. Render an audio file with the created score file in Csound. Make sure the samplerate is set to 48khz
3. Format the score file so that there are only i-statements. In other words, make the score file as simple as possible. (This was done using a short python script)
4. Parse the reformatted score file and generate a new file readable by Blender. In this case, it is a file with a bunch of lines saying dobounce(x,y) where x is the time of the strike, and y is the release. The parser was written in C to take advantage of the fscanf command.
5. Paste these new instructions in a Python script, which will be able to read them and directly work with Blender.
6. Run the Python script + generated score instructions inside of Blender. This will automatically create the necessary keyframes for the animation.
7. Render the animation to a video file.
8. Take the video file and the audio file and sync them together using mencoder. Since the audio is at 48khz, the audio and video should (hopefully) sync up perfectly.

And that is all there is to it!

Why this is so cool


This is a really cool breakthrough for me for a number of reasons. The biggest reason is because I finally figured out a way to incorporate visuals into my music in a simple, but complex way. Unlike most visualizers which take simply amplitude information from an audio file, mine took individual note information and parameters to render visuals. I just used start time and duration for animation parameters, but the possibilities are virtually endless! I believe visuals are especially important for 21st century music. Many times, the music is so out of touch with an average listener that it can be helpful to have a video to explain what the music is doing in order to gain a further appreciation of what is happening.

The second reason why I like this project so much is that it uses entirely open source software. Csound, Python, Blender 3d, and C are all under some sort of GPL or Creative Commons liscense. If there is anything that I want to stress in this blog it is this: the open source platform is the future of digital audio technology. I will repeat myself: the open source platform is the future of digital audio technology.

Thursday, January 19, 2012

Drummachine Tweaks and Github

This one will be short. Much shorter than it should be.

First off, I added a few more additions to my drum machine:

1. Added humanization. Velocities and timing will be randomly tweaked by a given amount.
2. Drums now have the ability to randomly "glitch." All this is is a really fast retrigger.  The percentage of the drum sounds that glitch is determined by a single value between 0 and 1.
3. function has an added "start time" parameter, which specifies what time the program should write the drum pattern. Useful for more complicated arrangements.

I made an 8-bar demo showing what my drum machine can do:





Csound Glitch Drums Test by The Zebra Project

Everything you hear was rendered from a Csound file. No post-processing or nothin'. Score generation for this was done using a small script in python I made in the summer called xm2sco. You can find a version of it here: xm2sco.sourceforge.net. It is still in early development, and will be going through some major changes. More to come on that. 

Would you like the code for this project? I made a github account and uploaded the code here

Monday, January 16, 2012

The Algorithmic Drum Machine, part 2

I'm slowly adding more and more to my algorithmic drum machine. Today I added the ability for my drum machine to reverse samples:


Algorithmic Drum Machine 2 by The Zebra Project

The first clip plays the drum pattern for four bars straight. The second clip plays the drum pattern for four bars with random variation and the new reverse effect.

It's pretty amazing to me how much life the reverse effect adds to the drums. I limited this example to only 4 bars, but I could make it any amount I want and it would all still be interesting due to the randomness. I used to make this sort of drum texture by hand using Renoise. This takes a split second to generate the score file.

Samples used are from the Vengeance Drum Sample pack. They have some pretty drum hits there, so I highly suggest you check it out.

My python script isn't all that different from the original drum machine. The only difference is an added reverse variable, set by a number between 0-1. A value of 1 will make 100% of the samples of that instrument reversed:

import random

#declare the base drum pattern in a typical 16th note cell fashion

no_weight = []

for i in range (16): no_weight.append(1)

snare_note =     (0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
snare_vel =     (0,0,0,0,1,.25,0,0,0,0,0,0,1,.1,.5,.5)
snare_weight =     (0,0,0,0,.9,.5,0,0,0,0,0,0,.9,.2,.1,.2)

kick_note =     (1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0)
kick_vel =     (1,0,0,0,0,0,0,0,0,0,1,0,0,0,.5,0)
kick_weight =     (1,0,0,0,0,0,0,0,0,0,1,0,0,0,.5,0)

hihat_note =     (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
hihat_vel =     (1,.1,.4,.25,1,.1,.4,.25,1,.1,.4,.25,1,.1,.4,.25,)
hihat_weight =     (.5,.6,.8,.8,.9,.8,.5,.6,.5,.6,.8,.8,.9,.8,.5,.6)

#open score file
score = open("drumscore.sco", "w")
tempo = 200

#write tempo
score.write("t 0 " + str(tempo) + "\n")

def drumseq(name,instr,note,vel,bar_num,weight, rand):
    score.write(";" + str(name) + "\n")
    time = 0
    for bar in range(bar_num):
        for i in range(16):
            rand_val = random.random()
            if note[i] == 1 and rand_val <= weight[i]:
                time = i * .25 + 4*bar
                rand_val = random.random()
                reverse = 1
                if rand_val < rand: reverse = -1
                score.write("i" + str(instr) + " " + str(time) +" .25 "+ str(vel[i]) + " " + str(reverse) + "\n")


#write the parts
drumseq("snare", 1, snare_note, snare_vel, 4, no_weight, 0)
drumseq("kick", 2, kick_note, kick_vel, 4, no_weight, 0)
drumseq("hihat", 3, hihat_note, hihat_vel, 4, no_weight, 0)
score.close()

I had to do some modifications to the Csound orchestra file in order to give the reverse option. Instead of using the soundin opcode, I used the diskin2 opcode, which will reverse the sound file if the frequency is a negative number. In my score, a p5 value of 1 would play a sound file normally, and a p5 value of -1 would reverse it. I also made some modifications so that the duration of the instrument would not exceed the length of the file. Without this, the sample would loop.

The orchestra code here took a little bit of creative thinking and research to figure out, so I'll post an example of one instrument:

instr 1
    iamp = .3
    ivel = p4
    ilen filelen "snare9.wav"
    p3 = ilen
    a1,a1 diskin2 "snare9.wav", p5, 0, 1
    outs a1*iamp*ivel, a1*iamp*ivel
endin


The next step in this project is going to be humanization, followed by possibly glitch and stutter. Here's to hoping I'll still have the interest by then!

Saturday, January 14, 2012

The Algorithmic Drum Machine

I kind of pulled a Mark Zuckerberg on this little project I made today, so I'll try to right my wrongs here:

Dan, this is your idea which I stole and implemented using Python and Csound. Please know that I did this out of love, and I am looking forward how you will implement your version of this drum machine in Supercollider.

Here is a little sample of what my drum machine sounds like:

Randomized Drum Machine Experiment by The Zebra Project

The drum sounds are just one-shot samples being triggered by the soundin opcode in Csound. No synthesis happening here. Actually, the code is so boring that I'm not going to even bother posting it. I won't be posting the samples either, but know that they are from the "Acetone Rhythm Ace" folder in this big file of drum samples I downloaded once.

The drum algorithm starts off with a base drum pattern. Inputting the base drum pattern is very similar to how you would program a traditional 16th note step sequencer. Every 16th note has a specific velocity and weight. Velocity speaks for itself. Weight is the hip algorithmic variable. Weight is a number between 0 and 1. The closer the number reaches 1, the more likely the number will be triggered. A note with a weight of .9 is going to get triggered 90% of the time with a specified velocity.

Below is the python code I used for the score generator. This code will render 4 bars of my example drum pattern to a Csound Score file. There, it can be rendered. Because this algorithm uses stochastic (random) elements, no two renders are alike.

import random

#declare the base drum pattern in a typical 16th note cell fashion

snare_note = (0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
snare_vel = (0,0,0,0,1,.25,0,0,0,0,0,0,1,.5,.5,.5)
snare_weight = (0,0,0,0,.9,.5,0,0,0,0,0,0,.9,.2,.1,.2)

kick_note = (1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0)
kick_vel = (1,0,0,0,0,0,0,0,1,0,0,0,0,0,.5,0)
kick_weight = (1,0,0,0,0,0,0,0,.9,0,0,0,0,0,.5,0)

hihat_note = (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
hihat_vel = (1,.1,.4,.25,1,.1,.4,.25,1,.1,.4,.25,1,.1,.4,.25,)
hihat_weight = (.5,.6,.8,.8,.9,.8,.5,.6,.5,.6,.8,.8,.9,.8,.5,.6)

#open score file
score = open("drumscore.sco", "w")
tempo = 120

#write tempo
score.write("t 0 " + str(tempo) + "\n")

def drumseq(name,instr,note,vel,bar_num,weight):
score.write(";" + str(name) + "\n")
time = 0
for bar in range(bar_num):
for i in range(16):
rand_val = random.random()
if note[i] == 1 and rand_val <= weight[i]:
time = i * .25 + 4*bar
score.write("i" + str(instr) + " " + str(time) +" .25 "+ str(vel[i]) + "\n")


#write the parts
drumseq("snare", 1, snare_note, snare_vel, 4, snare_weight)
drumseq("kick", 2, kick_note, kick_vel, 4, kick_weight)
drumseq("hihat", 3, hihat_note, hihat_vel, 4, hihat_weight)
score.close()



This is a rather basic implementation of this drum algorithm and has much room for improvements. In the future, I hope to incorporate more elements of processing like reverse and pitch shift in addition to humanization to strive to generate an organic sounding drum pattern.

Thursday, January 12, 2012

Synth Pads: the hardest sounds to do right

Today, I decided to try to design a synth "pad" sound. The thought of designing a pad really frightens me. You are essentially designing a patch where notes are meant to be held indefinitely. In a pad patch, a minute-long note should keep the audience interested right up to the last millisecond. This is a scary concept for me. How does one make an instrument where a single long note can be the opposite of boring?

So, I woke up this morning, fired up my laptop, took a deep breath, and came up with this humble example in Csound:
FM Pad by The Zebra Project

Here are some general concepts I thought about while making this sound:

1. Swell and Articulation:

When I designed pad sounds in the past, this one always got me. Every patch I made was just not articulate enough. I could only play really long notes, and this was a huge limiting factor for what the instrument could play. When designing this patch, I realized that pad swells are about growth in timbre, not volume. Articulation is extremely important for a versatile pad synth. Without it, your pad will always sound behind the beat. My patch has a volume envelope with an attack of 10ms and a separate "filter"(it's not really a filter, but we will call it that for now) envelope with an attack of 5 seconds.

2. Timbre and Change

A pad sound can't just be sawtooth wave. Listeners would be bored of it after the first few seconds. How the sound timbre changes over time determines the quality of Pad. Usually, I would have gone with a low-pass filter, but today I chose to use FM synthesis because you can do drastic changes to the waveform with minimal effort (it was also more interesting than a low-pass filter.) I was able to get a really interesting sound by slowly change the modulator number in the C:M ratio with a gentle LFO. I also put in a random number generator which adds very subtle deviation to pitch.

3.Wideness and Size

Creating width and size is the trick to giving your sound that overwhelming feeling. "Width" refers to the difference in sound between the left and right speakers. Slight modifications to each side gives the sound variety and realism. In my patch, I slightly detuned the left and right signals. "Size" refers to how large a sound is. The patch I have has 3 slightly detuned oscillators to give the sound of a large ensemble. To have made this a bigger sound, I could have added a large digital reverb. I didn't because it would have made the patch more complicated than I wanted it to be. Plus, I like to be careful with my reverb. It makes things messy very quickly and I almost consider it a cop-out when making good pad sounds. Reverb is like salt. It's good with the meal, but it isn't the meal.




Alrighty. That's all I have to say about that for now. Here is the Csound Code. Enjoy!


<CsoundSynthesizer>
<CsOptions>
-W
-o fmpad.wav
</CsOptions>
<CsInstruments>
sr = 96000
ksmps = 10
nchnls = 2
0dbfs = 1
instr 1
ipch = cpspch(p4)
iamp = p5*.15

;amplitude envelope with a fast attack
aenv linsegr 0, .0001, 1, 8, .9, 1, 0
;timbre modulation envelope with a slow attack
;this one changes the modulation index of the FM synth
kenv2 linseg 0, 5, 2
klfo lfo .01, .5

;random number generator. adds variety to the pitch.
krand randi .0005, 3

;3 detuned FM oscillators, sent to the right speaker
a1 foscil iamp*aenv, ipch*(1+krand)*.999, 1, 3+klfo, kenv2, 1
a2 foscil iamp*aenv, ipch*(1+krand)*1.002, 1, 3+klfo, kenv2, 1
a3 foscil iamp*aenv, ipch*(1+krand)*.996, 1, 3+klfo, kenv2, 1

;3 detuned FM oscillators, sent to the left speaker
a4 foscil iamp*aenv, ipch*(1+krand)*1.001, 1, 3+klfo, kenv2, 1
a5 foscil iamp*aenv, ipch*(1+krand)*1.004, 1, 3+klfo, kenv2, 1
a6 foscil iamp*aenv, ipch*(1+krand)*.998, 1, 3+klfo, kenv2, 1

aout = (a1+a2+a3)/3 ;combine the oscillators
aout2 = (a4+a5+a6)/3

outs aout2, aout
endin
</CsInstruments>
<CsScore>
f1 0 4096 10 1
t 0 70
;Score Generated using python and Milkytracker
i 1 0 2.0 9.02 1
i 1 2.0 2.0 9.01 1
i 1 0 4.0 7.02 1
i 1 0 4.0 6.02 1
i 1 0 8.0 8.02 1
i 1 0 8.0 8.05 1
i 1 0 8.0 8.09 1
i 1 4.0 4.0 9.0 1
i 1 4.0 4.0 6.1 1
i 1 4.0 4.0 5.1 1
i 1 8.0 2.0 9.02 1
i 1 8.0 4.0 8.04 1
i 1 8.0 4.0 8.07 1
i 1 8.0 4.0 8.09 1
i 1 10.0 2.0 9.01 1
i 1 8.0 4.0 6.09 1
i 1 8.0 4.0 5.09 1
i 1 12.0 2.0 8.07 1
i 1 14.0 2.0 8.04 1
i 1 12.0 7.0 8.02 1
i 1 16.0 3.0 8.06 1
i 1 12.0 7.0 8.09 1
i 1 12.0 7.0 9.02 1
i 1 12.0 7.0 6.02 1
i 1 12.0 7.0 5.02 1

</CsScore>
</CsoundSynthesizer>

Tuesday, January 10, 2012

Galbanum Waveforms

About a week ago, I purchased the Galbanum Architecture waveform pack on a really insistent impulse. For forty bucks, I downloaded 25,000 waveforms in wav32 format which are 2048 samples each. Besides offering many variations on classic waveforms like square, saws, and triangle waves, they also have a set of unusual waves. Many hours of experimentation lie ahead of me.

The problem is, how do I test each one? Waveforms are organized into different folders. Originally, I would go into a folder, load up a sample one by one in Renoise, and loop them. This was a time consuming effort.

Today, I figured out a way to do that in Csound.
<CsoundSynthesizer>
<CsOptions>
-odac
-M1
--midi-key-pch=4
</CsOptions>
<CsInstruments>
sr = 96000
ksmps = 10
nchnls = 1
0dbfs = 1
alwayson 2
instr 2

gktbl init 1
imax = 40
kkey sensekey

if kkey == 106 then ;go down if 'j' is pressed
gktbl = gktbl - 1
elseif kkey == 107 then ;go down if 'k' is pressed
gktbl = gktbl +1
endif

;cycle through the waveforms. if it reaches the end function tables, go to the beginning
if gktbl < 1 then
gktbl = imax
elseif gktbl > imax then
gktbl = 1
endif
if kkey == 32 then
printk2 gktbl
endif
endin

instr 1
;de-click the sounds
kpad linsegr 0, .01, 1, .01, 0
a1 oscil3 .3*kpad, cpspch(p4), i(gktbl)
out a1
endin

</CsInstruments>
<CsScore>
#include "tables" ;python generated file which contains 40 function tables with the waveforms
f 0 3600 ;stay open for an hour
</CsScore>
</CsoundSynthesizer>


The first thing I did was automatically generate all the wavetables to load up in Csound. With some google-fu and python, I created a file called "tables" which generated 40 function tables that could be loaded up into Csound. Each function table is a different waveform in the folder. To give you a sense of what these function tables look like, here is an example of one:

f1 0 2048 1 "Cos Saw.wav" 0 0 0

The synth itself is just an oscillator with some volume padding to prevent clicks. Just enough to get an idea of what the waveform sounds like. It takes realtime midi input from my USB keyboard, and I made it so the J and K keys would cycle through the waveforms. Pressing the space bar returns the function table number in the terminal window.

Hopefully this will be a useful tool for browsing through these waveforms!

Monday, January 9, 2012

Flux

In some ways, I have found that making music on a computer to be the exact opposite of making music on a traditional instrument. With a traditional instrument, one is always striving for perfection. With a computer, everything can be done "perfectly" right at the beginning. In fact, it is so perfect that doesn't sound musical at all. So while a traditional musician would spend his time striving for perfection, a computer musician would find himself chipping away at it.

Today I decided to play around a little with the idea of fluctuations ("flux," for the hip folks out there.)

Take a listen to these two Csound instruments I made, playing identical pieces of music:


Flux by The Zebra Project

Instrument A is nothing more than a simple triangle-wave oscillator with a volume envelope. Instrument B sounds very similar to instrument A, except with a few modifications. This was accomplished using two simple techniques:

1. Doubling and Wideness

A common producers technique is to duplicate an audio signal, add subtle variation to one of them, and then hard-pan each one left and right so that the two signals come out of separate speakers. This creates a very "wide" effect which can be especially heard in headphones.

To make this "wide" effect in instrument B, I made two oscillators with slight variations in tuning and in their volume envelopes, and sent one to the left speaker, and other to the right speaker.

2. Sample and Hold

Real instruments don't have perfect intonation, and neither should instrument B. Nuance is the key to creating expressive musical sounds. Pitch nuances can be made using a what is called a sample and hold generator. What exactly sample and hold generators do is beyond the scope of this post, so I highly recommend you read the synth secret article on it.

Instrument B has a sample and hold generator which generates a random number between 0 and 1 8 times a second. A value of 1 indicates that the pitch will get shifted by the maximum amount, and a value of 0 indicates no change at all. The depth of this change is determined by the variable idepth Instrument B.


For those interested, here is the code.


<CsoundSynthesizer>
<CsOptions>
;-odac ;realtime output
-o flux.aiff ;render to audio file

</CsOptions>
<CsInstruments>
sr = 96000
ksmps = 32
nchnls = 2
0dbfs = 1
instr 1
iamp = .2
ipch = cpspch(p4)

;one volume envelope
kamp1 linsegr 0, .0003, 1, .5, .05, .2, 0

;basic oscilator with no modulation
a1 oscil iamp*kamp1, ipch, 1

outs a1, a1
endin

instr 2
iamp = .2
ipch = cpspch(p4)
;sample and hold generator
krand randi 1, 8
;depth of modulation, where modulation is a number between 0-1 (best results < .05)
idepth = ipch* .005

;two volume envelopes, with subtle differences
kamp1 linsegr 0, .0003, 1, .5, .05, .2, 0
kamp2 linsegr 0, .0005, 1, .51, .05, .2, 0

;two oscillators with slight variations
a1 oscil iamp*kamp1, ipch*.998 + idepth*krand, 1
a2 oscil iamp*kamp2, ipch*1.002 + idepth*krand, 1

outs a2, a1 ;each oscillator sent to a different speaker
endin



</CsInstruments>
<CsScore>
f1 0 2048 7 1 1024 -1 1024 1 ;Triangle Wave
;Score Generated from a MIDI file made in Renoise and converted using another Csound instrument
i1 0.000000 0.913379 8.020000
i1 0.260771 1.304762 8.090000
i1 0.391383 1.434921 9.040000
i1 0.652154 1.434921 9.070000
i1 0.913152 1.173923 8.050000
i1 1.565306 0.521769 8.040000
i1 1.826077 0.260998 8.090000
i1 2.086848 0.913379 8.020000
i1 2.347846 1.304535 8.090000
i1 2.478231 1.435147 9.040000
i1 3.000000 1.174150 8.050000
i1 3.652154 0.782766 8.040000
i1 3.913152 0.652381 8.090000
i1 2.739229 2.087075 9.070000
i1 4.173923 0.913152 8.020000
i1 4.434694 0.913379 8.090000
i1 4.565306 0.913152 9.060000
i1 4.826077 0.913379 9.040000
i1 5.086848 0.913379 8.000000
i1 5.347846 0.652381 8.070000
i1 5.478231 0.521995 9.040000
i1 5.739229 0.260998 9.020000
i1 6.000000 1.304535 9.010000
i1 6.000000 1.304535 8.020000
i1 6.000000 1.304535 8.059999

i2 8.347846 0.913152 8.020000
i2 8.608617 1.304762 8.090000
i2 8.739229 1.434921 9.040000
i2 9.000000 1.434921 9.070000
i2 9.260771 1.174150 8.050000
i2 9.913152 0.521769 8.040000
i2 10.173923 0.260998 8.090000
i2 10.434694 0.913379 8.020000
i2 10.695692 1.304535 8.090000
i2 10.826077 1.434921 9.040000
i2 11.347846 1.174150 8.050000
i2 12.000000 0.782766 8.040000
i2 12.260771 0.652608 8.090000
i2 11.086847 2.087302 9.070000
i2 12.521770 0.913152 8.020000
i2 12.782539 0.913379 8.090000
i2 12.913153 0.913152 9.060000
i2 13.173923 0.913152 9.040000
i2 13.434694 0.913379 8.000000
i2 13.695692 0.652381 8.070000
i2 13.826077 0.521995 9.040000
i2 14.086848 0.261225 9.020000
i2 14.347846 1.304535 8.059999
i2 14.347846 1.304535 8.020000
i2 14.347846 1.304535 9.010000
</CsScore>
</CsoundSynthesizer>