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!

No comments:

Post a Comment