BetaBlocker DS test tones

After a week of heavy development on Germination X, and with a fast approaching performance, it seemed the time to dive back into Gameboy DS homebrew and get the bits and pieces of assembler code I’d been playing with together into something I could build more sounds from.

After getting the low level stuff working properly, I got busy making a bunch of audio scenes that I can trigger from Betablocker DS code.


Sounds hosted by archive.org

Mostly I’m doing wavetable based things, with lots of frequency and ring modulation. I was also pleased to find this simple resonant filter thanks to the ever fabulous musicdsp archive (and thanks to Paul Kellett for originally posting it):

// set feedback amount given f and q between 0 and 1
fb = q + q/(1.0 - f);

// for each sample...
buf0 = buf0 + f * (in - buf0 + fb * (buf0 - buf1));
buf1 = buf1 + f * (buf0 - buf1);
out = buf1;

The next step was to read Jasper Vijn’s excellent explanation of fixed point maths which I’ve used a bit on the Android but not really totally understood before. Mobile devices tend to only have integer maths at the hardware level, so if we restrict the calculations to fixed point it’s much faster and kinder to batteries than the floating point equivalent. Here is the fixed point version of the filter:

// we are using .10 fixed point (10 bits for the fractional part)
#define FX_SHIFT 10

// convert an int into to it's fixed representation
inline s32 fx(s32 i) { return i<<FX_SHIFT; }

// multiply two fixed point numbers (returns fixed point)
inline s32 fxmul(s32 a, s32 b) { return (a*b)>>FX_SHIFT; }

// f is cutoff frequecy, q is resonance, s is the filter state
void lpf(s16* dst, s16* src, u32 length, s16 f, s16 q, s16 *s)
{
    u32 fb = q+fxmul(q,fx(1)-f);
    for (u32 i=0; i<length; ++i)
    {
        s[0]+=fxmul(f,src[i]-s[0]+fxmul(fb,s[0]-s[1]));
        s[1]+=fxmul(f,s[0]-s[1]);
        dst[i]=s[1];
    }
}

Betablocker DS: Table feedback after Claudius Maximus

After getting some dates for gigs with Betablocker DS, I am spending some time looking into audio algorithms, and implementing them on the Gameboy DS. Last Thursday I spent some time at the TAI studio/bunker with Till Bovermann investigating these PD patches by Claudius Maximus:

The algorithm uses feedback to create sounds that take some time to play through a wide range of frequencies. It works by writing into the same buffer it’s playing, but at a different rate/position – the resulting ugliness suits the style of BBDS very much. As an aid to our understanding Till converted the algorithm to Supercollider, then over the next couple of days I managed to get it running with an inner loop of 9 instructions on the DS (could probably be optimised further, but I’m still a beginner):

@ ----------------------------------------------------
@ qrz_maximus: *dst, length, readpos, writepos [freq, *tab]
@ ----------------------------------------------------
        .global qrz_maximus
	.type   qrz_maximus, %function
qrz_maximus:
        push    {r4,r5,r6,r7}       @ push the registers we need
        ldr     r4, [r13,#20]       @ load freq from stack into r4
        ldr     r5, [r13,#24]       @ load *tab from stack into r5
        ldr     r6, .tablength      @ load the tablen into r6
.maximus_loop:
        ldrh    r7, [r5,r2]         @ load the sample into r7
        strh    r7, [r0], #2        @ write output: *dst=r7 dst++
        strh    r7, [r5,r3]         @ feedback into tab[writepos]=r7
        add     r2, r2, r4          @ readpos+=freq
        and     r2, r2, r6          @ mask readpos into range
        add     r3, r3, #2          @ writepos++
        and     r3, r3, r6          @ mask writepos into range
        subs    r1, r1, #1          @ length--
        bne     .maximus_loop       @ repeat until length zero
        mov     r0, r2              @ return readpos
        pop     {r4,r5,r6,r7}
        bx      lr                  @ exit
.tablength:
        .word   0x00003FF

And here it is running on autopilot with a test program in Betablocker:

Golden Medallions and in-game programming

Once the low level code for a Naked on Pluto bot is written in Scheme, it’s added by the game using secret commands which program the game inside itself, while it’s running. This means the game can be changed while people are playing it – which makes it much easier to add new things without worrying about the disruption caused by restarting the server. We can also work on the game collaboratively, at the same time this way.


(Programming a spybot with it’s behaviour)

Eventually the plan is to be able to program the bots fully within the game client – this is still a long term goal, but there are of course some fairly complex security problems with this idea.


(dressing a AudienceBot with another object)

Not all players have the ability to use these secret commands right now, in order to access them a player has to be carrying a special object (also known as a “Golden Medallion”). This allows you access to all areas of the game, including an “administration room” and various other secret powers.

Rainy sunday

A rainy Sunday, with only the dog for company, so in between walks I thought I’d try and learn some assembler. I’ve been unhappy with triggering samples with Betablocker DS (I prefer synthesis) and I’ve heard good things about ARM asm – so it seemed like a good opportunity to attempt a small, fast and dirty synth.

I found some really nice tutorials here and here. I’ve done a tiny bit of this sort of thing before with microcontrollers, but this is a more of a respectable flavour of assembler, on a decent RISC processor (which derives from the Acorn Archimedes and is now used on IPhones, Androids and Gameboys). Here is a white noise generator:

; white_noise(r0=*dst, r1=clock, r2=length, r3=freq)
white_noise:
        push    {r4,r5,r6}          ; need to restore registers we use
        mov     r4, r1              ; r4 is the rand state (start with clock)
        ldr     r5, .rnd_data       ; r5 is the multiplier value
        ldr     r6, .rnd_data+1     ; r6 is the addition value
.noise_loop:
        mla     r4, r5, r4, r6      ; the maths bit: r4 = (r6 + (r5 * r4))
        strh    r4, [r0], #2        ; *dst++ = clock; 
        subs    r2, r2, #1          ; length--;
        bne     .noise_loop         ; branch if length not zero
        pop     {r4,r5,r6}
        bx      lr                  ; return
.rnd_data:
        .word   0x000343FD          ; nicked from ansi c rand()
        .word   0x00269EC3          ; need to keep large numbers (>8bit) as data

This code is based on the ansi C rand() function that basically looks like this:

randnum = randnum * 214013 + 2531011;

Which we can do in a single instruction – mla (multiply with accumulate). Of course, gcc would presumably optimise much better code than mine from C++, but there is something more satisfying about doing it this way. I certainly prefer the sound – and over half the cpu usage remains unused with 5 voices and the interface running. The rest of the code is here.

Betablocker machine running on Supercollider

Is seems our meetings at the TAI studio are bearing fruit already, Till Bovermann has ported the Betablocker machine as a Supercollider UGen. What’s interesting is rather than taking a similar approach to music making, this version is running at audio rate and the processes directly generate sample data. He can also run lots of them at the same time and control them from SCLang. It’s great when people use your code, but even better when it gets used in ways you didn’t think about.