atolf lftoa

using supercollider i reverse-engineered two old max/msp externals from cycling'74. they came as part of the pluggo installer and were compiled in the cfm binary format. this format is since long defunct and cfm externals can't be loaded into max/msp running under windows or newer intel macs (afaik). luckily i could still run the externals and helpfiles under max4.6 on my old ppc mac.

and as far as i could tell, the source code for these binaries were never released. so i took the trial&error route and managed to figure out how they work internally by using simple input strings like 'aa', 'ab', 'ac', 'ba', 'bb', 'aba', 'abc' etc. then i just observed the output arrays of floating point numbers and tried to mimic that in supercollider code. it was fairly quick to come up with the algorithms that encode (atolf) and decode (lftoa) shown below.

also a note on max vs sc: no way i could have solved this using max/msp only. algorithms like these are horrendous to implement with patchcords. see the mess in the screenshots below. also max/msp floatinpoint numberboxes as well as the [print] object does not show the whole 32bit float values! they round off to 6 digits after the decimal point. why? so max/msp can calculate just fine using 32bit floats as long as you don't try to print or output them in any way.

anyway, i first wrote RedALF for supercollider (it is now in the redSys quark) and from that i then patched f0.atolf and f0.lftoa (now part of my f0.abs max/msp abstractions).

(
~atolf= {|str|
        var res= [1/2**5];
        var tre= [2**12, 2**20, 2**28];
        str.do{|chr, i|
                var j= i.div(3);
                if(i%3==2, {
                        res= res++(1/2**5);
                });
                res.put(j, res[j]+(chr.ascii/tre[i%3]));
        };
        res;
};
~lftoa= {|arr|
        var res= "";
        arr.do{|val|
                var a, b, c;
                val= val-(1/2**5)*(2**12);
                a= val.asInteger;
                val= val-a*(2**8);
                b= val.asInteger;
                val= val-b*(2**8);
                c= val.asInteger;
                res= res++a.asAscii++b.asAscii++c.asAscii;
        };
        res;
};
)
a= ~atolf.value("aber")   //--> [0.055025476962328, 0.05908203125]
~lftoa.value(a)  //--> "aber"