Friday, September 4, 2009

Drum Variation Algorithm

The context
I've been experimenting a bit with the Arduino as a basic midi sequencer. A drum sequencer is a good place to start. It's easier than an actual melodic music sequencer. You can leave out the length of a note, as a drum is a one-shot sounds device.

Because allowing the user to program drum sequences himself requires an extensive interface, or a piece of software, I thought I would write a drum generator.

Wouldn't it be cool if you can just push a button and a computer/chip does the whole creative process for you?

Yes, it would. But it scares me a little bit as well.

I've started with a mechanism that chopped up existing drum sequences in pieces and reassembles them to generate new drum sequences. This could work for breakbeat style drum patterns, but most of the time it seemed to create a build up of expectations, only to leave the listener behind with an empty feeling.


The drum sequence format
Because the format in which the drum sequence is saved on the Arduino is essential to the Drum Variation Algorithm, I will explain this first.

The size of the RAM memory of the Arduino (based on an Atmega168) is small. Really small. Only 1kB. 1024 bytes. 8192 ones and zeros.

I'll just pause here for a while to let this sink in, I suggest you do the same.

Alright, if I want to use lots of data structures, I will have to make them small. The best way to make data small, is to assume as much as you can about the data in question and limit the possibilities as much as possible. So I introduced three limitations.

The drum pattern has a maximal resolution of 16th notes

For one instrument, the maximal number of notes that can be played in one measure is 16


There are only four velocity levels

Midi allows 128 velocity levels, I've made a mapping from 0, 1, 2, 3 to 0, 40, 90, 110 respectively (off, soft, medium, hard)


A measure consists of a maximum of three instruments

A typical measure consists of a hi-hat, a snare and a bassdrum, but which instruments are used is configurable



So if a measure has sixteen notes with four velocity levels, one measure for one instrument can be encoded in 4 bytes.

This is a typical drum notation which is used a lot online.
I've used large and small X's to indicate the velocity level.

HH|X-x-X-x-X-x-X-x-|
SD|----X-------X---|
BD|X---------x-----|


In the datastructure I've described above, this would look something like this. (A B in front of ones and zeros is the binary representation of a number: 11 = B1011 = 0xB)

{
{ 42, B11001000, B11001000, B11001000, B11001000 },
{ 40, 0, B11000000, 0, B11000000 },
{ 36, B11000000, 0, B00000100, 0 }
}

The first number defines the instrument as a midi note number. 42 is a hihat, 40 a snare drum and 36 a bass drum. The total amount of bytes needed to encode a measure of 3 instruments with a maximal resolution of 16th notes requires ... 15 bytes.

A clearer representation would be a number in base 4, but afaik this is not possible in C/C++. B11001000 would be 3020, so a hard hit on the first 16th note, nothing on the second, a medium hit on the third and nothing on the fourth.


The Drum Variation Algorithm

If you've gotten this far, the algorithm itself is actually really simple, I hope it is not too much of a let down. If it is, I will gladly remind you of Occam's Razor.

Everytime a new measure starts, each byte of the datastructure (except the instrument note numbers) is bitwise XOR'ed with a random byte (a number between 0 and 256). The actual random number being calculated is one between 0 and a variable limit [controlled by a potmeter]. If the number is greater than 255, the original byte is left alone. With this you can control the amount of introduced variations.

Why bitwise XOR? It seems good at keeping the feel of the original pattern. It introduces new notes, but an XOR is also affected by the original byte. A bitwise OR can only add notes and a bitwise AND can only take them away.

Here is a video demonstrating the algorithm, the knob controls the amount of introduced variations (it also demonstrates the BBox Drum Generator, a post about this will be here soon).


I love it when simple things give good results :)

6 comments:

  1. Hier en daar veel te low level naar mijn goesting, maar op vele vlakken volledige geniaal: de doos! het algorithme! de datastructuur! en vooral een luisterbare beat!
    Zoveel beter dan die drumgenerator die je in je eerste jaar informatica geschreven hebt ;)
    U rule!

    ReplyDelete
  2. Om af te lekken! Blij dat het af is!

    To lick off! Happy that it is off!

    ReplyDelete
  3. This is amazing.

    If this slave-synced to MTC and re-output MTC with random midi notes added to the stream, and you had your basic beats preprogrammed on a drum machine. . . you wouldn't need storage for patterns, therefore wouldn't need to XOR the random number with the pattern data (which would be nonexistent) and also wouldn't need the lcd. Which would make room for more midi notes to send. It could very possibly be just a blank box with a midi in, a midi out and a probability knob for each drum/note being sent (the midi notes could be set up ahead of time depending on the machine you're using).

    Are you interested in building things for other people?

    Actually I kind of need it. How hard is arduino? I've never made anything like this. I did DIY som sound ROMs for my HR-16B. That was as easy as burning a CD - kind of (the sound design took the longest. But soldering and programming chips and electronics is a whole different thing.

    I think drum patterns need a little variation (even if you keep the knob low, like 10%), but it's difficult on some machines (impossible on others) when juggling a live electronics hardware setup.

    Ooh, and maybe a second knob per drum for the note quantize. . .

    ReplyDelete
  4. First of all, just adding random notes in a midi stream won't do much good, because then it would only be able to add notes to a drum pattern, it would not be able to remove them. The XOR also seems to keep the feel of the pattern. If you have no knowledge about the pattern and you are just going to send midi notes, it would introduce variation, but I'm not convinced it would yield good results.

    Second, Arduino isn't very hard if you have some experience in C/C++ programming and a basic knowledge of electronics.

    And if I would be interested in building stuff... I'm always interested in building stuff :)

    ReplyDelete
  5. I had to go lookup bitwise XOR and think about it. I can definitely see how it would keep the feel of the original beat. The bbox is awesome. I definitely think you've come up with an elegant solution.

    I guess, if you had no knowledge of an arbitrary pattern on an external machine that you might try to supplement (without being able to take any drums away, of course), you could use a few basic beats for the hi-hats (1/4notes, 1/8notes, 1/16notes and upbeats) like:

    HH|X---x---X---x---|
    HH|X-x-X-x-X-x-X-x-|
    HH|XxXxXxXxXxXxXxXx|
    HH|--X---x---X---x-|

    and for simple snare patterns, some choices like this:

    SD|--------X-------|
    SD|----X-------X---|
    SD|----X-----------|
    SD|------------X---|

    for bass drums you can't assume a whole lot, except that quite often, there will be a bass drum on one:

    BD|X---------------|

    ___________________________________________

    You could purposefully not program the basic hi-hat pattern, basic snare pattern or kick-on-one (the parts of the pattern that would be triggered from the bbox) into the external machine; you would just program the rest of what the loop needs. Also, you could use a different drum pad for the random drums being introduced to have a slightly different sound. This way the beat would be half steady (the pattern in the external machine) and half random (from the bbox). and could help animate a static looping beat.

    It would probably need midi in and out for sync and all that.
    ___________________

    Anyhow, my overthinking OCD-ness aside, the point being: the bbox is really cool and inspired me to think about how it could be applied to the way I make music and just might get me off my ass to learn about microcontrollers.
    ____________________
    Thanks.

    ReplyDelete
  6. There is no such thing as overthinking :)

    Think about these things hard enough, and you come up with something original.

    If the step to microcontrollers is too big. You could also just start with programming on a PC. There are enough midi libraries out there.

    ReplyDelete