Ranking (fft frames) using only vanilla objects? (mp3-ification)

Rodrigo's icon

I've been using this custom external for the ranking of fft frames to produce an mp3 type compression. I really dig the sound of it, particularly when used with bit/sample reduction or other extreme distortion.

Now what I have works great, but it's mac only (which makes sharing the patch difficult), and is also 32bit. So I want to try to remove the dependency altogether, if possible.

Now I kind of understand sorting algorithms (framerank~ uses combsort if I understand correctly), but I have no idea how this kind of sorting is handled in Max, much less fft max.

Here is the patch and external.

And here is the .c from the xcode project:

//////////////////////////////////////////////////////////////////////

#include "ext.h"
#include "z_dsp.h"
#include

/*
framerank~ is an object to average the values of a specific number of fft frames.
*/

void *this_class;

typedef struct _framerank
{
t_pxobject x_obj;

    long *indices;

} t_framerank;

void *framerank_new (long windowsize, long size);
t_int *framerank_perform(t_int *w);
void framerank_dsp(t_framerank *x, t_signal **sp, short *count);
void framerank_free(t_framerank *x);
void framerank_assist (t_framerank *x, void *b, long m, long a, char *s);

int main(void)
{
setup((t_messlist **) &this_class, (method) framerank_new, (method)framerank_free, (short)sizeof(t_framerank), 0L, A_DEFLONG, A_DEFLONG, 0);
addmess((method)framerank_dsp, "dsp", A_CANT, 0);
addmess ((method)framerank_assist, "assist", A_CANT, 0);
dsp_initclass();

    return 0;
}

void *framerank_new(long windowsize, long size)
{
t_framerank *x = (t_framerank *)newobject(this_class);

    dsp_setup((t_pxobject *)x, 1);
    outlet_new(x, "signal");

    x->indices = 0;

return (x);
}

void framerank_free(t_framerank *x)
{
    dsp_free(&x->x_obj);
    if (x->indices)
        free (x->indices);
}

void combsort_indices_float (long *indices, float *data, long num_points)
{
    long gap = num_points;
    long swaps = 1;
    long index;
    long gap_index;
    long i;

    while (gap > 1 || swaps)
    {
        if (gap > 1)
        {
            gap = (gap * 10) / 13;
            if (gap == 9 || gap == 10)
                gap = 11;
            if (gap < 1) gap = 1;
        }

        for (i = 0, swaps = 0; i + gap < num_points; i++)
        {
            index = indices[i];
            gap_index = indices[i + gap];
            if (data[index] < data[gap_index])
            {
                indices[i] = gap_index;
                indices[i + gap] = index;
                swaps = 1;
            }
        }
    }
}

t_int *framerank_perform(t_int *w)        // Here we just store the incoming vals if we are taking a sample and then decide when to output
{
    float *in = (float *)(w[1]);
    float *out = (float *)(w[2]);
    int vectsize = w[3];
    t_framerank *x = (t_framerank *)(w[4]);

    long *indices = x->indices;
    long i;

    if (x->x_obj.z_disabled)
        goto out;

    for (i = 0; i < vectsize; i++)
        indices[i] = i;

    combsort_indices_float(indices, in, vectsize);

    for (i = 0; i < vectsize; i++)
        out[indices[i]] = i + 1;

    out:
    return w + 5;
}

void framerank_dsp(t_framerank *x, t_signal **sp, short *count)
{
    free (x->indices);
            x->indices = malloc (sizeof(long) * sp[0]->s_n);

    dsp_add(framerank_perform, 4, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n, x);
}

void framerank_assist(t_framerank *x, void *b, long m, long a, char *s)
{
    if (m == ASSIST_OUTLET)
        sprintf(s,"(signal) Ranking");
    else
        sprintf(s,"(signal) FFT Data In");
}

5419.mp3.zip
zip
Rodrigo's icon

Ok, thinking about this further I'm thinking I might be able to get there doing some kind of spectral gate, where only bins above a certain threshold pass through. Though not exactly ordered, it's unlikely they would have the same magnitudes, so adjusting the threshold should drop out bins one at a time.

Basically like the spectral gate in the MSP examples.

Though this doesn't sound as interesting as framerank. With a low setting in framerank you get all these fft/bubbly kind of things, where as the spectral gate sounds very gate-y regardless.

Not sure what's different about those two approaches though.

Rodrigo's icon

Here's a comparison between the two.

5422.Archive.zip
zip
gola's icon

Hi, did you get any further with this? I am experimenting with similar idea. Too bad framerank is only 32 bit...

Rodrigo's icon

Nope, nothing further.

BUT you'll be pleased to know framerank~ is now 32/64 (attached).

framerank.mxo_.zip
zip
gola's icon

Thanks! Still would be nice to have it vanilla... and perhaps be able to tweek the innards of the framerank somewhat for more variation.

gola's icon

...and still get some error message trying to use it in 64bit max: "msp object needs to be updated for msp64", but you are sure it is recompiled? Thanks for all help!

Rodrigo's icon

Ah weird, yeah I see that. I guess I hadn't tested it properly since I'm still running 32bit for the most part.

It's also a different type/color error too, I've mainly seen that red "could not load" error, instead of this more polite yellow "framerank~: msp object needs to be updated for msp64".

Francisco Botello's icon

Was this ever checked out? That damn message still pops up.

Rodrigo's icon

Not really no. I've just tried going about it in a different way unfortunately.