Archive

Posts Tagged ‘max msp’

Euclidean sequencer – Max for Live version

March 26th, 2010

Some people have expressed an interest in my Euclidean sequencer patch getting ported to max for live. Ummm, it’s like nearly there. Any minute now, look…

Image of euclidean sequencer running in live

Euclidean sequencer ported to max 4 live.

I’ve been playing with this little baby for a week now, the algorithmic sequencer works nice. Programming wise I’ve been getting bogged down in preset management but after having decided to ditch live’s presets and just stick with max’s xml files it’s nearly there. I wish the live number boxes had settable max and minimum parameters but they don’t.

This is my first patch in max for live and the new purchase is nice and everything but I can see it just being another barrier between me and music making. That and the fact the sparse documentation just confuses me leaves me grumpy. Ho hum.

Software , , ,

MPEG7 Encoder for MaxMSP alpha release now here !

June 26th, 2009

A third of what drove my tv installation piece was the audio analysis software that allowed me to segment, analyse and database the sound track of youtube movies. These had been stripped from the downloads and saved as wavs. At first I wrote a simple slicer and segmenter in VASP that allowed me to get basic amplitude spectral data for entry into a database. But this was hacky, the output data wasn’t standardised making it useless to use with other patches and crashy (it would analyse solidly for ten minutes then crash Max in annoying fashion). So I came back to an MPEG7 audio encoder written under LGPL in Java.

I’d looked at Holger Crysandt’s library early on in my PhD when I was playtesting ways of getting good audio metadata but ended up sticking with Tristian Jehan’s analyzer~ external. This works great with with signals in real time but if you want to analyze say ten minutes of sound then it takes the ten minutes to play it through analyzer~ and log the details. My desire for faster than realtime, offline analysis, was largely what drove me to write a wrapper in max Java around Holger’s library.

Alpha release is here !

Alpha release is here !

The alpha release is now finished and I’m posting a jar file for windows. UPDATED:  NOW MAC COMPATIBLE.

This alpha release includes an example application patch showing off the slicing abilities and a reference text file to talk you through the numerous attributes of the external (though this is a work in progress, you will need to refer to Holger’s website and the MPEG7 audio standard for lots of useful details).

frecycle is a recycle clone entirely in max msp

frecycle is a recycle clone entirely in max msp

The frecycle patch is modelled on Propellerhead’s beat mash up defining Recycle. Simpy load a mono audio wav and drag the slice threshold bar to the right to increase the number of slices. These are automatically mapped to midi keyboard keys starting at midi note number 36. The pitch bender gives +/- 50% pitch range and the funky autosequence gives good results with one or two bar drum loops with the slice threshold moderately low. Enjoy!

To install the alpha release simply download the zip and follow the installation instructions in INSTALL.txt.

DL: Mpeg7Encoder-alpha-distro-mac-compatible.zip

The technically enclined may enjoy the source code at the project’s Sourceforge page.

Hopefully next week I’ll follow up with my meta sampler patch that allows you to use the SQL database to auto map sounds according to their spectral features.

Other stuff, Software , , ,

5 reasons why you need analysed segmented audio

June 8th, 2009

I checked my google analytics page today and found my bounce rate was over 80%. After having taken the time to find out what that meant I read google’s (not at all evil) guide to writing web headlines. Hence the title.

I’ve spent the past fortnight polishing up an external I wrote to analyse, segment and store information on sounds in MaxMSP, there are a couple of other objects that do similar stuff like Jehan’s analyzer~ or the mac only and now defunct slice~ but I wanted something that could work offline, automated and in a database friendly fashion. The version I came up with to achieve this uses a fairly thick wrapper, written in mxj, around Holger Crysandt’s java MPEG7 encoder.So what are the five reasons why this might be any use to you?

  1. How often do you find yourself wishing you had a simple beat slicer like that of recycle, kontakt or live in max that didn’t need a load of patching on your part but could just be dropped in to work with files or audio? I work with libraries of breakbeats in my music making and spend a lot of time slicing, plus for generative art pieces as I am wont to create, segmenting audio is often the first step in reappraising and changing existing works into new ones.
  2. Wouldn’t it be nice if when the slicing was finished rather than grouping kicks, snares, hats and other percussion by hand you could let the computer do it for you? A slicer that has inbuilt audio analysis is the first step for doing this.
  3. When you’re working on a beat and you want to try similar sounds wouldn’t it be nice if the computer could suggest similar sounds from a set you’ve specified? Analysed audio with good metadata can make this possible.
  4. Isn’t life too short to spend an age cutting and labelling every beat before deciding if they even work in a track? By using automated tools for cutting up audio you could test many sounds, find surprising new relationships before saving the segments for use in whatever package you fancy.
  5. Segmented, meta-data heavy audio file formats such as MPEG7 open up some interesting new possibilities for generative and interactive audio as well as regular music applications, why not get ahead on an emerging standard by spending a few hours knobbing about with it in everyone’s favourite graphical patching language?

That’s it, those were my five reasons, and if you don’t click on the below photo for a closer look at my MPEG7 external development then my bounce rate will only increase. Expect a buggy beta this week.

Screenshot of MPEG7 encoder and database externals for MaxMSP, writing helpfiles and proper documentation are some of the least fun things I do

Screenshot of MPEG7 encoder and database externals for MaxMSP, writing helpfiles and proper documentation are some of the least fun things I do.

Blogging, Music, Software , , , , ,

Euclidean beat generator redux

June 8th, 2009

After developing my euclidean beat generator for use in my Journey through a burning brain exhibit and reading some of the feedback from other users, I have developed some new features. This version is fully pattrstorage compatible allowing interpolation between beat presets. This came out of a conversation I had with a user I met on the max forums who had put the patch to use with his own genetic algorithms using brain waves as a fitness test. I was pretty impressed with what he’d done and was delighted to see a photo of his patch on David Zicarelli’s look back at expo ‘74.

Expo '74 Attendee patch running EEG (brainwave) controlled genetic algorithms for better euclidean beats. Photo by attendee John Manoogian III.

Expo '74 Attendee patch running EEG (brainwave) controlled genetic algorithms for better euclidean beats. Photo by attendee John Manoogian III.

Future versions will include less buggy gui recall and the ability to specify simple strings to the js object that program the sequences.

Euclidean beat generator 1.01, now with added preset interpolation, discover the grooves between the grooves

Euclidean beat generator 1.01, now with added preset interpolation, discover the grooves between the grooves

Euclid Max Source Patches: EUCLID.zip

Euclid Standalone: euclid_standalone.zip

Software , , ,

Euclidean algorithmic beat generator

April 4th, 2009
euclid

Euclidean rhythm generator with minimalist sequence visualizer

After stumbling upon an interesting thread on the max forums, reading Godfried Toussaint’s interesting paper on the subject and checking out some other similar creations across the internets, including a vst, ruby and lisp implementation I decided this sounded interesting enough to devote some time to and perhaps a good excuse to learn some scripting for Max. I won’t bother going over how Euclid’s algorithm works for sequencing beats as it is detailed very well in the paper and this blog post by Ruin & Wesen. Instead I’ll focus on how I made the patch and the things I learnt along the way. For those who just want the patch to play with I’ll post the links here to save you a whole load of scrolling. I’ve also built a standalone version for those without Max who want to get in on the whole algorithmic beat generation thing.

euclid_patches.zip Max 5 Patcher file and js

euclid_patches.zip Max 5 standalone

Scripting the creation, connection and destruction of Max objects from inside Max itself is pretty much the last thing in the instruction manual. I think is because of the weight Cycling put into the idea that Max is a graphical programming language for non-programmer types. While I think it’s great that Max appeals to arty programming phobes I like programming and and I’m arrogant enough to think I’m pretty good at it. I also periodically yearn for ‘for’ loops and proper conditional logic while patching without resorting to convoluted chains of uzis, gates and less-than objects. I think some people are really good at using Max that way and can mangle a coll into doing their evil bidding through shear patch magic, but I get annoyed after three clicks when I know I could achieve the same task in a single line in a ‘proper’ programming language.

As such I’ve become increasingly enamoured with Max’s js and mxj objects that allow you to program in javascript and java respectively, as well as Thomas Grill’s really nice py external which allows for python scripting inside Max. For this project I quickly decided on js as I wanted to try out some auto patch generation. As most of the gui objects have their creation scripted I don’t have to bother monotonously naming each of them and pixel pushing them into alignment. This is js’s first really nice feature but I quickly learnt that it’s best if your js checks for the existence of an object before creating one or you have to delete all your objects before you reload your altered js program every time you make a change.

In the rhythm sequencer I wanted boxes for the number of steps, pulses, accents, offset, accent offset and midi note number and I wanted a set of these boxes for each rhythm part. This is what the first part of the code achieves.

//maximum number of parts
var maxparts = 16;

//x and y to start drawing boxes from
var px = 30;
var py = 500;

//inlets and outlets
inlets = 1;
outlets = 1;

//global variables
var p = this.patcher; //saves typing
var numparts;

//Maxobj variables for scripting
var step_boxes = new Array(maxparts);
var s_message = new Array(maxparts);
var pulse_boxes = new Array(maxparts);
var p_message = new Array(maxparts);
var accent_boxes = new Array(maxparts);
var a_message = new Array(maxparts);
var offset_boxes = new Array(maxparts);
var o_message = new Array(maxparts);
var aoffset_boxes = new Array(maxparts);
var ao_message = new Array(maxparts);
var note_boxes = new Array(maxparts);
var n_message = new Array(maxparts);
var seq;
var lcd1;
var lcd2;
var lcd_width = 300;
var lcd_height = 600;

//arrays for holding steps, pulses, accents and offsets and midi note numbers
var steps = new Array(maxparts);
var pulses = new Array(maxparts);
var accents = new Array(maxparts);
var offsets = new Array(maxparts);
var aoffsets = new Array(maxparts);
var outnote = new Array(maxparts);

//array for all the sequences
var riddims = new Array();

//useful number
var deg2rad = 2 * Math.PI / 360

//executed on startup
function loadbang() {
    post("euclidean rhythm generator - robin price 2009\n");
    //do comments
    step_comment = p.getnamed("step_comment");
    if (step_comment == null) {
        step_comment = p.newdefault(px, py + 20, "comment", "@text", "Steps", "@varname", "step_comment", "@presentation", 1);
    }
    pulse_comment = p.getnamed("pulse_comment");
    if (pulse_comment == null) {
        pulse_comment = p.newdefault(px + 60, py + 20, "comment", "@text", "Pulses", "@varname", "pulse_comment", "@presentation", 1);
    }
    accent_comment = p.getnamed("accent_comment");
    if (accent_comment == null) {
        accent_comment = p.newdefault(px + 120, py + 20, "comment", "@text", "Accents", "@varname", "accent_comment", "@presentation", 1);
    }
    offset_comment = p.getnamed("offset_comment");
    if (offset_comment == null) {
        offset_comment = p.newdefault(px + 180, py + 20, "comment", "@text", "Offset", "@varname", "offset_comment", "@presentation", 1);
    }
    aoffset_comment = p.getnamed("aoffset_comment");
    if (aoffset_comment == null) {
        aoffset_comment = p.newdefault(px + 240, py + 20, "comment", "@varname", "aoffset_comment", "@presentation", 1);
        aoffset_comment.message("set", "Accent\nOffset");
    }
    note_comment = p.getnamed("note_comment");
    if (note_comment == null) {
        note_comment = p.newdefault(px + 300, py + 20, "comment", "@varname", "note_comment", "@presentation", 1);
        note_comment.message("set", "Output\nNote");
    }
    //other scripted objects
    seq = p.getnamed("seq");
    if (seq == null) {
        seq = p.newdefault(1000, 1000, "seq~");
        seq.message("sendbox", "varname", "seq");
    }
    lcd1 = p.getnamed("lcd1");
    if (lcd1 == null) {
        lcd1 = p.newdefault(900, 900, "lcd", "@border", 0, "@ignoreclick", 1, "@presentation", 1);
        lcd1.message("varname", "lcd1");
        lcd1.message("size", lcd_width, lcd_height);
    }
    lcd2 = p.getnamed("lcd2");
    if (lcd2 == null) {
        lcd2 = p.newdefault(900, 900, "lcd", "@border", 0, "@ignoreclick", 1, "@bgtransparent", 1, "@presentation", 1);
        lcd2.message("varname", "lcd2");
        lcd2.message("size", lcd_width, lcd_height);
        p.bringtofront(lcd2);
    }
    for (i = 0; i < maxparts; i++) {
        steps[i] = 16;
        pulses[i] = 4;
        accents[i] = 2;
        offsets[i] = 0;
        aoffsets[i] = 0;
        outnote[i] = 60 + i;
        //step boxes and messages
        step_boxes[i] = p.getnamed("step_" + i);
        if (step_boxes[i] == null) {
            step_boxes[i] = p.newdefault(px, py - i*25, "number", "@minimum", 1, "@maximum", 128, "@varname", "step_" + i);
        }
        step_boxes[i].set(steps[i]);
        s_message[i] = p.getnamed("step_message_" + i);
        if (s_message[i] == null) {
            s_message[i] = p.newdefault(px, 100 + py + i*25, "message", "@varname", "step_message_" + i);
        }
        s_message[i].message("set", "step", i, "\$1");
        p.connect(step_boxes[i], 0, s_message[i], 0);
        p.connect(s_message[i], 0, this.box, 0);
        //pulse boxes and messages
        pulse_boxes[i] = p.getnamed("pulse_" + i);
        if (pulse_boxes[i] == null) {
            pulse_boxes[i] = p.newdefault(px + 60, py - i*25, "number", "@minimum", 0, "@varname", "pulse_" + i);
        }
        pulse_boxes[i].set(pulses[i]);
        pulse_boxes[i].message("maximum", steps[i]);
        p_message[i] = p.getnamed("pulse_message_" + i);
        if (p_message[i] == null) {
            p_message[i] = p.newdefault(px + 60, 100 + py + i*25, "message", "@varname", "pulse_message_" + i);
        }
        p_message[i].message("set", "pulse", i, "\$1");
        p.connect(pulse_boxes[i], 0, p_message[i], 0);
        p.connect(p_message[i], 0, this.box, 0);
        //accent boxes and messages
        accent_boxes[i] = p.getnamed("accent_" + i);
        if (accent_boxes[i] == null) {
            accent_boxes[i] = p.newdefault(px + 120, py - i*25, "number", "@minimum", 0, "@varname", "accent_" + i);
        }
        accent_boxes[i].set(accents[i]);
        accent_boxes[i].message("maximum", pulses[i]);
        a_message[i] = p.getnamed("accent_message_" + i);
        if (a_message[i] == null) {
            a_message[i] = p.newdefault(px + 120, 100 + py + i*25, "message", "@varname", "accent_message_" + i);
        }
        a_message[i].message("set", "accent", i, "\$1");
        p.connect(accent_boxes[i], 0, a_message[i], 0);
        p.connect(a_message[i], 0, this.box, 0);
        //offset boxes and messages
        offset_boxes[i] = p.getnamed("offset_" + i);
        if (offset_boxes[i] == null) {
            offset_boxes[i] = p.newdefault(px + 180, py - i*25, "number", "@minimum", 0, "@varname", "offset_" + i);
        }
        offset_boxes[i].set(offsets[i]);
        offset_boxes[i].message("maximum", steps[i] - 1);
        o_message[i] = p.getnamed("offset_message_" + i);
        if (o_message[i] == null) {
            o_message[i] = p.newdefault(px + 180, 100 + py + i*25, "message", "@varname", "offset_message_" + i);
        }
        o_message[i].message("set", "offset", i, "\$1");
        p.connect(offset_boxes[i], 0, o_message[i], 0);
        p.connect(o_message[i], 0, this.box, 0);
        //accent offset boxes and messages
        aoffset_boxes[i] = p.getnamed("accent_offset_" + i);
        if (aoffset_boxes[i] == null) {
            aoffset_boxes[i] = p.newdefault(px + 240, py - i*25, "number", "@minimum", 0, "@varname", "accent_offset_" + i);
        }
        aoffset_boxes[i].set(aoffsets[i]);
        aoffset_boxes[i].message("maximum", pulses[i] - 1);
        ao_message[i] = p.getnamed("accent_offset_message_" + i);
        if (ao_message[i] == null) {
            ao_message[i] = p.newdefault(px + 240, 100 + py + i*25, "message", "@varname", "accent_offset_message_" + i);
        }
        ao_message[i].message("set", "accent_offset", i, "\$1");
        p.connect(aoffset_boxes[i], 0, ao_message[i], 0);
        p.connect(ao_message[i], 0, this.box, 0);
        //note boxes and messages
        note_boxes[i] = p.getnamed("note_" + i);
        if (note_boxes[i] == null) {
            note_boxes[i] = p.newdefault(px + 300, py - i*25, "number", "@minimum", 0, "@maximum", 127, "@format", 4, "@varname", "note_" + i);
        }
        note_boxes[i].set(outnote[i]);
        n_message[i] = p.getnamed("note_message_" + i);
        if (n_message[i] == null) {
            n_message[i] = p.newdefault(px + 300, 100 + py + i*25, "message", "@varname", "note_message_" + i);
        }
        n_message[i].message("set", "note", i, "\$1");
        p.connect(note_boxes[i], 0, n_message[i], 0);
        p.connect(n_message[i], 0, this.box, 0);
    }
    notifyclients();
    calculate(-1);
    parts(1);
    bang();
}

 This seems fairly dense at first but mostly it’s just doing the same thing over and over again to create all the number boxes along with a message box that allow us to update our variable inside js. I chose this method of creating each number box connected to a personalised message box because js in Max has no native method of reading the contents of a screen object. Hence the workaround, each group of objects, step, pulse boxes or whatever are created connected to a message box which is connected to the js object. The message boxes are formatted so that when the user changes the number in any of the gui boxes a method is called that tells js which box changed and what number it now carries. This allows for a user interface where each of the boxes is updated as the other entries are changed. This lets you add nice features like number boxes that update the other boxes around them so they cannot display nonsensical values, i.e. a rhythm part with more pulses than steps to hold them.

Looking through the code you can see first off I define a maxparts global variable which sets the maximum number of rhythm parts and thus groups of number boxes the script creates. I then create variables to control where the patch starts creating the objects in the patcher window and the number of inlets and outlets on the js box itself. The variable p is just to save typing this.patcher every time I want to do something with the patcher and numparts describes the number of active rhythm parts at the present time. Next I create references to all of the objects I’ll create and access in the script, for the most part these references are stored in arrays as there are so many of them and doing so allows for thing like iterating across them. Then I create arrays to hold the settings for each rhythm part and an array that will hold all the sequences that have been generated.

The loadbang() is executed when the patch is started just like a loadbang in the patch, this creates the comments, number and message boxes and a few other goodies. Note the form for each object.

step_comment = p.getnamed("step_comment");
if (step_comment == null) {
    step_comment = p.newdefault(px, py + 20, "comment", "@text", "Steps", "@varname", "step_comment", "@presentation", 1);
}

First I try and get a reference to an object in the patch and then I check if that reference is null, if it is it’s obviously been clobbered or something so I recreate it. This way whenever you reload a js during its development it doesn’t create multiple copies of the same set of objects.

Next I define a set of functions that will be called by the user changing the values of the number boxes. These allow the script to take care of updating the other boxes and the seq~ object whenever anything changes. Here is the function for the step boxes.

function step(n, val) {
    if (n >= 0 && n < maxparts && val >= 0 && val <= 128) {
        //number of steps must always be greater than or equal to the number of pulses
        if (val >= pulses[n] && val > offsets[n] && val >= accents[n]) {
            steps[n] = val;
            pulse_boxes[n].message("maximum", val);
            offset_boxes[n].message("maximum", val - 1);
        } else {
            if (val < pulses[n]) {
                pulses[n] = val;
                pulse_boxes[n].message("set", val);
                pulse_boxes[n].message("maximum", val);
                if (val <= aoffsets[n]) {
                    aoffsets[n] = val;
                    aoffset_boxes[n].message("set", val - 1);
                    aoffset_boxes[n].message("maximum", val - 1);
                }
            }
            if (val <= offsets[n]) {
                offsets[n] = val - 1;
                offset_boxes[n].message("set", val - 1);
                offset_boxes[n].message("maximum", val - 1);
            }
            if (val < accents[n]) {
                accents[n] = val;
                accent_boxes[n].message("set", val);
                accent_boxes[n].message("maximum", val);
            }
            steps[n] = val;
        }
        notifyclients();
        calculate(n);
        programme_seq(n);
        bang();
    } else {
        post("steps message needs two integers between 0 0 and " + maxparts + " 128\n");
    }
}

This function starts by checking the values it’s been passed (which number box got changed, n, and it’s new value, val) make sense and then goes on to update the internal representation steps[n] and update the other number boxes in the rhythm part if the new value requires it. Finaly it causes the new rhythm to be calculated, programmes the seq~ and redraws the graphics which I’ll discuss after touching on the next noteworthy function.

function parts(i) {
    if (arguments.length) { //bail if no arguments
        a = arguments[0];
        if (a < 0) a = 0;
        if (a > maxparts) a = maxparts;
        numparts = a;
        for (z = 0; z < maxparts; z++) {
            if (z < numparts) {
                step_boxes[z].message("presentation", 1);
                pulse_boxes[z].message("presentation", 1);
                accent_boxes[z].message("presentation", 1);
                offset_boxes[z].message("presentation", 1);
                aoffset_boxes[z].message("presentation", 1);
                note_boxes[z].message("presentation", 1);
                programme_seq(z);
            } else {
                step_boxes[z].message("presentation", 0);
                pulse_boxes[z].message("presentation", 0);
                accent_boxes[z].message("presentation", 0);
                offset_boxes[z].message("presentation", 0);
                aoffset_boxes[z].message("presentation", 0);
                note_boxes[z].message("presentation", 0);
                clear_seq(z);
            }
        }
        notifyclients();
        bang();
    } else {
        post("parts message needs integer argument between 0 and " + maxparts + "\n");
    }
}

This nugget of javascript allows us to change the number of currently active rhythm parts and update the visible elements of the patch so we’re not distracted by anything that isn’t doing anything.

As for calculating the rhythm this is taken care of by the calculate() function which gets the euclidean sequence for a given number of pulses and steps, the sequence for a number of accents and pulses, applies any rotation to the either sequences (using code I stole from here) and applies the accents to the rhythm. Actually most of the work is done by sub functions eugen() and apply_accents().

function eugen(s, p) {
    var r = new Array();
    if (p >= s || s == 1 || p == 0) { //test for input for sanity
        if (p >= s) {
            for (i = 0; i < s; i++) { //give trivial rhythm of a pulse on every step
                r.push(1);
            }
        } else if (s == 1) {
            if (p == 1) {
                r.push(1);
            } else {
                r.push(0);
            }
        } else {
            for (i = 0; i < s; i++) {
                r.push(0);
            }
        }
    } else { //sane input
        pauses = s - p;
        if (pauses >= p) { //first case more pauses than p
            per_pulse = Math.floor(pauses / p);
            remainder = pauses % p;
            for (i = 0; i < p; i++) {
                r.push(1);
                for (j = 0; j < per_pulse; j++) {
                    r.push(0);
                }
                if (i < remainder) {
                    r.push(0);
                }
            }
        } else { //second case more p than pauses
            per_pause = Math.floor( (p - pauses) / pauses);
            remainder = (p - pauses) % pauses;
            for (i = 0; i < pauses; i++) {
                r.push(1);
                r.push(0);
                for (j = 0; j < per_pause; j++) {
                    r.push(1);
                }
                if (i < remainder) {
                    r.push(1);
                }
            }
        }
    }
    return r;
}

function apply_accents(r, a) {
    var offset = 0;
    var out = new Array(r.length);
    for (b = 0; b < r.length; b++) {
        if (r[b] == 1) {
            if (a[offset] == 1) {
                out[b] = 1;
            } else {
                out[b] = 0.5;
            }
            offset += 1;
        } else {
            out[b] = 0;
        }
    }
    return out;
}

Eugen() is basically the most important part of the whole thing as it implements the algorithm for the distribution of the beats. When the rhythm is programmed the seq~ object in the Max patch is updated by the programme_seq() function. This sends a sequence of messages to the named seq~ object in the patch (no need for patch cables, we can send them direct) that programmes the id number and midi notes into the seq~.

function programme_seq(arg) {
    clear_seq(arg);
    r = riddims[arg];
    for (l = 0; l < steps[arg]; l++) {
        if (r[l] == 1) {
            seq.message("add", 0, l / steps[arg], arg, outnote[arg], 127);
            seq.message("add", 0, l / steps[arg] + (1 / steps[arg] - 1 / 256), arg, outnote[arg], 0);
        } else if (r[l] == 0.5) {
            seq.message("add", 0, l / steps[arg], arg, outnote[arg], 100);
            seq.message("add", 0, l / steps[arg] + (1 / steps[arg] - 1 / 256), arg, outnote[arg], 0);
        }
    }
}

programme_seq.local = 1;

function clear_seq(arg) {
    if (arg == -1) {
        for (h = 0; h < maxparts; h++) {
            seq.message("delete", 0, 0.0, 1.0, h);
        }
    } else {
        seq.message("delete", 0, 0.0, 1.0, arg); //delete all entries for sequence
    }
}

clear_seq.local = 1;

The last part of the js takes care of the ultra minimalistic sequence visualization. At first I tried using Max’s jsui object but I found it is an exceptional CPU hog so I created two lcd objects one for the sequence and one for the red line showing the playback location. The red line lcd has a transparent background and sits on top of the other sequence visualizer. This way when ever the playback line is redrawn we don’t have to redraw the rest of the sequence visualization. This is a really good example of using js’s procedural (as opposed to graphical) logic to send a set of messages to a Max object, this would be tricky (for me at least) to achieve with native Max graphical methods.

function draw() {
    lcd1.message("clear");
    var rowheight = (0.5 * lcd_height) / numparts;
    for (y = numparts - 1; y >= 0; y--) {
        var boxwidth = lcd_width / steps[y];
        var arcwidth = 360 / steps[y];
        var arcradius = (lcd_width/2) * (y + 1) / numparts;
        var r = riddims[y];
        for (x = 0; x < steps[y]; x++) {
            if (r[x] == 1) {
                lcd1.message("frgb", 0, 0, 0);
                lcd1.message("pensize", 1, 1);
                lcd1.message("paintarc", lcd_width/2 - arcradius, lcd_width/2 - arcradius, lcd_width/2 + arcradius, lcd_width/2 + arcradius, x * arcwidth, arcwidth + 2);
                lcd1.message("paintrect", boxwidth*x, lcd_height - rowheight*(y+1), boxwidth*(x+1), lcd_height - rowheight*y);
            } else if (r[x] == 0.5) {
                lcd1.message("frgb", 100, 100, 100);
                lcd1.message("pensize", 1, 1);
                lcd1.message("paintarc", lcd_width/2 - arcradius, lcd_width/2 - arcradius, lcd_width/2 + arcradius, lcd_width/2 + arcradius, x * arcwidth, arcwidth + 2);
                lcd1.message("paintrect", boxwidth*x, lcd_height - rowheight*(y+1), boxwidth*(x+1), lcd_height - rowheight*y);
            } else {
                lcd1.message("frgb", 255, 255, 255);
                lcd1.message("pensize", 1, 1);
                lcd1.message("paintarc", lcd_width/2 - arcradius, lcd_width/2 - arcradius, lcd_width/2 + arcradius, lcd_width/2 + arcradius, x * arcwidth, arcwidth + 2);
            }
        }
    }
    for (y = 0; y < numparts; y++) {
        var boxwidth = lcd_width / steps[y];
        for (x = 0; x < steps[y]; x++) {
            lcd1.message("frgb", 255, 255, 255);
            lcd1.message("linesegment", boxwidth*x, lcd_height - rowheight * y - 1, boxwidth * x, lcd_height - rowheight * (y+1));
        }
    }
}

function settime(time) {
    lcd2.message("clear");
    lcd2.message("frgb", 255, 0, 0);
    lcd2.message("linesegment", ((time + 0.001) * lcd_width) % lcd_width, lcd_height/2, ((time + 0.001) * lcd_width) % lcd_width, lcd_height);
    lcd2.message("linesegment", lcd_width/2, lcd_height/4, lcd_width/2 + (lcd_width/2) * Math.sin(-time*Math.PI*2 - Math.PI), lcd_width/2 + (lcd_width/2) * Math.cos(-time*Math.PI*2 - Math.PI));
}

That pretty much covers most of what my patch is doing, in the future I hope to update it with some interesting swing and shuffle options by sending the phasor~ signal through a table lookup waveshaper and some industrial sounding msp beatbox voices.

Music , , ,

MTE1007 Assignment 2 Help

January 14th, 2009
Don't worry i is from tech support

Don't worry I is from tech support

I gave a tutorial today to half my class on how to get started with their second MaxMSP assignment. Just to make things fair on those that didn’t come I’ve posted a tidier version of where we ended up. Remember this patch doesn’t do everything you will need to include in your final patch to get all the marks, it’s just meant to brush the away the Christmas cobwebs and get you started. If you have any questions leave them as comments, that way other people can read them and save time if they’re stuck on the same point.

Here is a zipped copy of the patches, you can supply your own sound file or use Eric’s while experimenting but remember your final submission must use the one he posted on QOL. Good luck.

Uncategorized ,

Homebrew midi-cv box

January 12th, 2009
midiDAC and double bass pitch and amplitude tracker.

Homebrew midiDAC with integrated double bass pitch and amplitude tracker.

After having built a x0xb0x this summer which I fitted with Brian Castro’s x0xio back panel mod I decided a good project to make would be to make a midi-cv converter box. Although the x0x comes with it’s own midi in, the firmware is a bit tempremental and I was getting a lot of skipped notes and no control over slides when programming midi sequences for the x0x in Ableton. After having played for more time than I care to admit to with the x0x I’ve come to the conclusion that although the internal sequencer rocks, especially when using the SokkOS firmware (funky pattern randomise not to mention the other extra features) the midi response is a bit naff.

This formed half the motivation for building a midi-cv box, the other came from my practice as a double bass player. The double bass being fretless lends itself to slides just like the 303, with my new pitch CV in could I take the pitch and amplitude of double bass and use it as a control signal for my x0x ? More on this side of the project later. The brief I set myself for the midi-cv side was simply that it should supply at least 5 cv outs with a resolution high enough to allow for some interesting tuning options later on. I also wanted proper midi in although I knew while I was programming the firmware I’d probably just send the midi byte code over USB .

midiDAC with integrated double bass pitch and amplitude tracker.

midiDAC close up, the lid contains the inputs and outputs for the pitch tracker

Having looked around the Arduino forums I found a lot of people using the PWM outputs on the Arduino and just running them through a low pass RC filter to get a smooth variable DC voltage out. This has the benefit of being quick to make but the downside of non-linearity across the domain of the duty cycly and the range of voltage out and the small portamento this approach will neccessarily come with. Having decided against using the PWM out and having recently been introduced to the analog devices catalogue by an a electronics friend I decided to get hold of one of their AD5668 DAC chips and dive into the world of surface mount chips and SPI. I’m not claiming to be the first to hook up a DAC chip to the Arduino as there’s a fair amount of evidence people have taken the same approach when building their own cv boxes but the approach worked and I’m pretty pleased with the results.

The AD5668 and an adaptor to make soldering wires on to a 5mm chip slightly easier, came to about twenty quid from Farnell. The rest of the box materialised over a period of about two weeks as I made nightly visits to my long suffering local Maplin (I swear they hate me in there, there’s only so many times you can roll in at ten to eight and ask for an opto-isolator and a bag load of assorted components).

Under the hood of the midiDAC

Under the hood of the midiDAC

Although optoisolators aren’t technically neccessary for midi input I’m a bit of a stickler for standards and seeming as I’d never used one before I figured I might as well. This Arduino forum post came in handy for the midi in part of the circuitry and the midi byte parsing, I particularly enjoyed the mspaint circuit diagram. As you can see the box is packed pretty tight and the eight outputs which are on switched mini-jacks and quarter inch jacks barely fitted in the enclosure. The pitch and amplitude tracker I built for my double bass is on a circuit board blu-tacked to the inside of the lid so you can’t see it in this photo but I’ll cover that in another post.

The most time consuming part was reading the AD5668 datasheet forwards, backwards and in random access until I’d squeezed all the functionality I wanted out of it. It uses a 32 bit address space with 4 bit padding at either end, 8 bits for commands and 16 for resolution on the output which swings between 0 and 5v. There’s a fair bit of left and right shifting in the arduino source code as well as some bit masking which is kind of funky if you’re into powers of two.

There already exists a fair wealth of material (e.g. here, here and here) on how to get the Arduino to deal with midi byte code so after having successfuly hooked up the Arduino to the DAC chip (SPI really isn’t that hard given the Arduino’s built in shiftOut method, reading this helped) I just started hacking apart kuk’s midi parsing code for my own purposes. I’ve put the source code here so you can get a head start on making your own if you’re interested in using the AD5668 or just seeing a project that makes broader use of the midi specification. There’s a fair amount of code dedicated to getting pitch and amplitude data from the double bass which you’ll have to scroll past.

Having documented the insides of my midiDAC I’ll leave you with two videos showing its implementation with my x0xb0x. I cooked up a little random scale generator in Max to play on 16th notes and synched the whole thing up to my drum machine via Ableton and Rewire (Max 5’s new transport still doesn’t accept MTC as a clock source, hence Ableton and Rewire joining the party). Enjoy.

Hardware , , , , ,

Introducing the ir2midi box

January 12th, 2009

Another part of my forthcoming interactive tv installation is the hardware infrared to midi box I built for interfacing old tv remotes with max and jitter. This was a pretty simple project based around the now ubiquitous Arduino microcontroller and a rather handy i.r. receiver chip I picked up for next to nothing from Sparkfun.

The IR remote control to midi tool box.

The IR remote control to midi tool box.

The box plugs in to my computer using USB and a max patch takes care of churning out the midi to whatever application I fancy. As well as using it for my installation I use it for controlling Ableton while standing a.f.k practicing bass. I included a hardware reset switch on the top which I hardly ever use since the latest Arduino’s support software reset when loading firmware and seem much happier with Max’s port object.

I stuck on two LEDs to give some user feedback, green for power and red for code received. I initially tried to write my own firmware for decoding the signals but after googling around a bit I came across this guy’s code which worked much better than my own attempts and saved me about three weeks work. Basically the box just chucks out a unique hex code for any button on any remote that’s sufficiently close to the RC5 Philips standard which seems to be most of the ones in my house. Max takes care of assigning each code/button to a MIDI message, like note, program change or continous controller but I might in the future go back and shift this functionality from Max into the hardware. When I’m using it with Ableton I just route the midi back from Max to Live using midiYoke.

Under the hood of the ir2midi.

Under the hood of the ir2midi.

Looking inside you can see there’s not much going on here, just the Vishay TSOP85 receiver and the circuitry for the LEDs and reset switch (this is on the flip side of the vero board but it’s just some pull down resistors). The nice thing about the receiver was it came with the neccessary circuitry integrated so all I had to do was wire it up to the power and one of the digital inputs on the Arduino. I’ve recently become obsessed with socketing things so I can pull them out and swap/replace them as I see fit so I used a few of these yummy modular connectors from Maplin. That’s where I got hold of the frosted blue enclosure which lets through the i.r. signal unimpeded as well as looking quite shhhexy (as much as a blue see through box can).

Introducing the Vishay TSOP85

Introducing the Vishay TSOP85

That pretty much covers it. I’m pretty pleased with it as it is, the whole thing only cost about £30 and took not too long to build. In the future I’ll post up the Max patch, circuit diagram and a video showing it’s integration with Ableton. Changing scene with the channel change and controlling volume, stop, start, record, etc by remote is really quite handy for me as I play double bass and constantly putting it down just to stop/start is a pain in the arse.

Hardware , , , , ,