Convert external to gen codebox?

Rodrigo's icon

So I have this external (by Alex Harker) that I've been using for mp3-ification of sound in my patch. It sounds and works awesome. But it's just an .mxo, and a 32bit one. I've been trying to convert my patch to a project to share more easily, but once it's flattened into a project, it's much harder for end users to replace individual files depending on the operating system they use. Up to now I just had windows users replace the poly~ file with a version that doesn't use the external, and they were good to go. With a maxproject, that's not an option anymore.

I'm wondering if the external can just work inside a codebox.

I pasted the .c inside codebox and it's not working, and throws up errors I don't understand:

gen_domain: dsp.gen: [string "gen2.Operators"]:711: expr/codebox object missing expression
gen~: failed to compile patcher

So I'm wondering if it's a syntax thing that needs to change, or if it is more complex than that, and will require refactoring the code altogether.

Here is the gen object with the code pasted in:

Max Patch
Copy patch and select New From Clipboard in Max.

This is how the actual external is being used.

Max Patch
Copy patch and select New From Clipboard in Max.

And here is the unedited .c file, as codebox changes it a bit:

#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");
}

Chris Johnson's icon

hey Rodrigo! found this thread after finding and reading this one: https://cycling74.com/forums/ranking-fft-frames-using-only-vanilla-objects-mp3-ification/
I was super excited... but then I saw it was Mac only. Then THIS thread got me excited again (read in your post that you had something working for Windows users)... and then read further and got sad again. so the big question is: did you ever get this issue resolved? would LOVE to be able to do this live and on the fly; otherwise I'll be spending a lot of time manually mp3-ifying Ableton drum racks and setting up chain-switching and that's just a whole lot more work and less flexibility than I really want...

Rodrigo's icon

@Chris

Archive.zip
application/zip 24.87 KB

Attached is a stripped back demo patch along with a compiled version of the external for windows (I've never been able to test the win version personally)

Chris Johnson's icon

wow, thanks for the quick reply! I'll check this out and report back.

Chris Johnson's icon

so after testing and further research it seems there are some problems with certain externals on Windows versions after 7. I'm running Windows 10 and can't get any version of Max that I own (tried Max 7 standalone in 32- and 64-bit versions and Max 8 for Live 10) to recognize framerank~ as an external. best solution I can find involves recompiling the external: https://cycling74.com/forums/error-126-loading-external . I probably do not have anywhere near the knowledge required to reverse-engineer this thing so this will probably be the end of the line for me (unless you have some advice on tackling this issue/making a modern version of the mp3-ifyer for 64-bit versions of Max).

Rodrigo's icon

Yeah that would be the external not being compiled correctly. Hopefully I can bypass the requirement altogether. I'll post here if/when I do.

Fora's icon

Hey @rodrigo, how did you get on with importing external code into gen~? I am hoping to do the same and was wondering if you managed to successfully get it compiled?

Rodrigo's icon

No, not really looked at it in a while. I did ask a (lurking?) friend to have a look at it, but not heard back about it yet.

Will post here if I get on with it.

Fora's icon

Cheers, I will dive into it as soon as I can also, will report any findings

JFS's icon

Anyone know if the framerank external is under another name or perhaps composable in Mr Harker's framelib package? It doesn't seem to exist there as an external of the same name, unfortunately..

Rodrigo's icon

Nope unfortunately. It was a one-off external that has sadly been sunset.

That being said, if you are using Framelib, a friend of mine made an adaptation that does the same thing using that.

Max Patch
Copy patch and select New From Clipboard in Max.

This needs to live inside a poly~, but this will do what framerank did, as well as add some new functionality. The 'detail' parameter sounds really nice, and now with mp3ify you can go from 0-100% as well as going down to -100%, so a kind of inverse mp3ification.

Obviously this is not real mp3 compression, but it has that sound.

JFS's icon

awesome, thanks to you and your friend 🙏