gen with integers (for MPE MIDI data handling)?


    Nov 29 2021 | 11:01 am
    Hi, I'm starting to look into (message domain) gen to handle 14bit 3D MPE MIDI data (from Sensel Morph). I read that variables are type-less, but I suppose that means everything is in float (or double?)? Is there a way to use ints, for more efficiency and the "<<" bit-shift operator? Cheers!
    [For the curious, it would replace this beautiful FTM message box expression, ideally with acces to an external [table] object m storing the current ctrl values:]

    • Nov 30 2021 | 4:16 pm
      No, gen doesn't support integer-formatted numbers or bit shifts, and it's not likely to in the near future. But with modern desktop processors, the performance loss from doing everything in floating point is not as severe as it used to be. Most current top-end desktop processors can complete a floating-point add instruction in two clock cycles and a multiply in four, and they are heavily pipelined, so as long as you don't stall the pipeline alot, you won't actually see much performance difference on Intel or AMD. In the Husserl tutorial series on this forum, tutorials 1 and 3 go way into pipeline optimization methods.
      I don't know the specifics for the current M1 on floating point but I wouldn't expect much from it, as the company is really motivated to make profit on glitz these days. Most of Apple's customer don't really know the difference between floating point and integer calculation, so it's not likely to be that impressive.
    • Nov 30 2021 | 5:43 pm
      like ernest says it is really no problem to handle midi as floats (any powermac G3 is fast enough to calculate the all the midi data you can at a maximum need to drive a setup of 16 10-port midi interfaces even you use javascript for it :P ), but of course that means that you have to translate the bitshift operators you might be used to, to something else. (i am not even sure why recently people start doing such simple things using gen and gen~)
    • Nov 30 2021 | 5:51 pm
      The reason I do midi on gen is that js runs on the low-priority thread, so the latency is indeterminate, with maintenance of all screen drawing operations consuming almost an entire core. So I only use js for bank operations and multi changes.
    • Nov 30 2021 | 7:44 pm
      sure, i wouldnt use js either. but midi is kind of the core discipline of max, isnt it. :)
    • Nov 30 2021 | 9:08 pm
      Thanks for your insights. Sure, handling 6 MIDI controllers costs next to nothing, compared to audio. It's just the engineer in me cringing at that non-optimality =-) especially since gen is compiled on-the-fly anyway, so it would be just a matter of replacing "double" by "int" in the generated intermediate C code. (It is double for gen, isn't it? which makes it a bit more costly, or did recent processors catch up with that, too?)
    • Nov 30 2021 | 9:29 pm
      in danger if of beeing inaccurate: max uses 64 bit numbers since 6.x as soon as you also enable 64 bit audio, and is 64 bit only since 7.x and there never was a different size of its int and float numbers. besides that, objects like expr or log were 64 bit internally since ever. (though i am not sure what happens when you use logical-or inside expr. bitshift... does not even exist there)
      optimisation? ... while accessing an external table?
    • Dec 01 2021 | 8:01 am
      in danger if of being inaccurate
      that danger is real... While audio is 64bit, data in lists, atoms, flonum, and buffer~ is still 32bit single precision float in Max.
      i am not sure what happens when you use logical-or inside expr
      You mean the expr external? Well, there, unlike in gen, you do have a way to explicitly declare arguments as integer ($i1), and the bit-shift and logical operators seem to cast their args to int.
      optimisation? ... while accessing an external table?
      You're right, that would be less efficient since it would require locking. Actually, an internal integer array only managed by gen would be best, here.
    • Dec 01 2021 | 5:50 pm
      Actually gen/gen~ *will* use integers in code generation if it knows it is safe to. E.g., if you route inputs through an [int] operator, the output will be cast to int in the generated code. If you multiply two of these, the result will be `int`, etc., until it meets something that isn't `int` (or an operator that can't be integer, e.g. [sin]), and in that case it will cast the input as `double` and the output will be `double`. The best way to see this is to look at the code exported to see where/when it can happen.
      (Note: It will also use `bool` types where it can).
      But even if gen wasn't able to infer integer for a specific operation, note that 64-bit floating point numbers can accurately represent integers up to +/-(2^53)-1 (so long as you maintain only whole number operations on them). That's a significant range.
      The performance cost differences here are negligible. Moreover, the underlying compiler that turns this into machine code is pretty smart at optimizing numerics and types; I wouldn't worry about this too much. Especially given how small the task is here.
      I will say though, I do think it might be nice to introduce bitwise operations to gen; there's just a lot of caveats and gotchas to think through first.
    • Dec 01 2021 | 6:23 pm
      @Graham
      Thank you very much for all your comments and remarks. Now I see many new possibilities related to my own ”gen experience” ;-)