Anybody written a Max External for EigenLite API

I just got @thetechnobear 's eigenlite working on a Mac laptop – I’m wondering if anybody has built a Max external for this API that can be easily brought into Max?


1 Like

my MEC project has a max external
however, I don’t think Ive tried to build/run it for years

was built for max 7, but external has probably not changed.

anyway I’d not treat it as an out the box solution , rather as an idea on how to make it work.

note: it also uses the mec-api rather than eigenlite api, but the apis are very similar.

(iirc, actually this external started out on eigenlite, but I then move it to MEC)


btw: @David somewhere I read (not sure now where now?) you thought the LED part of the api was not working… I dont think thats true, I use from MEC and it works fine.

also perhaps bring @Kai into this
Im believe Kai wrote something that wrapped around EigenLite or MEC? (EigenMapper?) that made this all a little more user friendly :slight_smile:

also as a user of gig performer Im sure working together could be really fruitful.

(I personally think a tight integration with GigPerformer, mid-term would be much more satisfying than using Max!?)

oh, I should also tag @keymanpal , as he knows the status of all these kind of things better than I !


Well, my hope is to build an extension for GP using our new SDK but I still have a ton of stuff implemented in Max with some extremely convenient abstractions. For example:



The arguments to Eigen.Scale.Guitar are the base transpose amount and the desired MIDI channel.

In this example, both aftertouch and pitchbend are automatically available for each key.

This opens up to the following where each icon flashes as you touch the real key

Finally, this one allows me to “write” on the keyboard, the LEDs form letters in the desired color


Yeah the key group type functionality is non-trivial.

The only thing I wasn’t too keen on with the max external was how I had to get the async data back on to correct max thread… this is pretty important to get right … and if you do your own max external you might want to check this mec external to see what I was doing.
( of course you might have better ideas too, as I don’t consider myself any kind of max expert - far front it ;))

1 Like

@david What I did was wrap EigenLite in a console app and send the data on localhost as OSC. I intend to make it into a VST instead - or perhaps as a GigPerformer extension? Makes more sense to host it inside GigPerformer than having to start it manually.

I find that EigenLite works well - lights included. The issues I know of and intend to look at soonish are:

  • Tau inverted axis (roll? yaw? I never can remember which is which) for the Tau is the opposite of Pico/Alpha
  • Some Tau lights aren’t mapped correctly. Pico and Alpha lights are fine
  • USB issue (at least on on my MBP with USB-C ports only) - currently I have to first plug the cable into the mac, then the base station. The other way around doesn’t work, weirdly enough. Same behaviour in EigenD. Same with various USB-C → A adapters and hubs.

…none of them that serious, really.

I was planning to continue working on this during the easter holidays. So if there is any overlap with what you have in mind, I’ll gladly coordinate a bit with you.

I don’t have big short-term plans for EigenMapper (the VST that maps the OSC data to midi). A low-hanging fruit is assigning chords to single keys, so I’ll probably add that, at least.


Hmm, that is precisely what I’m doing right now – I managed to create an xcode project using JUCE so I can leverage the OSC classes there. As I have a large collection of Max patchers that interpret OSC coming from the older eigenD (thanks to @gbevin who created that for me many years ago) per my earlier post, reproducing those same OSC messages is my first priority — that will allow me to continue using my Max patchers with Gig Performer for some upcoming shows.

As for a VST vs GP extension, that really depends of course on whether you want it to be usable from other plugin hosts.

Right now I’m also just trying to isolate what I actually need, do some documentation cleanup, etc. I’d also like to move away from the dynamic libraries and statically link them instead and also turn the ihx files into resources (defined via Projucer) so that after I do a build, I end up with a single package that I can just put on any machine without having to worry about where libraries are installed, etc

1 Like

odd it looks like its the same as the alpha … which is wrong? perhaps the firmware is reporting it inverted?

ah, I think thats a simplification… when I chucked the leds in, I assume the coarses were all the same length, but of course thats not true with the Tau.
having the courses different lengths on the Tau is a pain for generalisation :wink:

( I also didn’t have a tau at the time, so didn’t really test it much… I really should fix up a few of the tau oddities now!)

1 Like

Yeah, that is on my to-do list as well. If you do this I’d be interested in the result. Setting up C++ dev/build environments is very far from my day-job dev work, so anything related to that tends to be a bit of a pain-point for me.

I don’t have access to my Tau right now (we bought an apartment in Lyon a year ago and live there parts of the year! But the Tau and Alpha is in Norway), but iirc up/down was inverted. I assumed it was a firmware difference, but didn’t investigate.

Hah, yeah, I cursed the different lengths when making the Mapper VST. :slight_smile: From memory, I think course/key# out of EigenLite is fine, but for the lights one or both button rows map to the normal keys. So they end up “fighting” over the same leds.

Both should be easy fixes, so I can make a pull request once I’m back in Norway (if you haven’t already looked at them by then).


yeah, I just multiply course by a fixed number, which is what’s causing the overlap.
really for eigenlite I need to make 2 changes:

a) device callback
change so it sends back and array of course lengths, so that each can be different.
b) change led call to use this ‘course length’ array

both trivial changes…

as for things like vsts, I did actually go down that route in MEC (see mec-vst),
however, at the time there are very little support for MPE within daws, so it wasn’t really that valuable, so I chose a ‘host within host’ route, which was quite a bit more complicated :slight_smile:

if you go down the vst route, you’ll want to check that (mpe) midi output from vsts is actually supported, many daws (Ableton looking at you!) have some odd ideas in this area when I last looked… basically the MPE support is ofter the tracking input level.

the other issue with doing as a vst, is daws will not record a vsts midi output.
Unless you direct it to another track… and then again, you start hitting limitations with daws when doing t1 → t2 mpe midi.

also with mpe midi you start to have to make decisions about voicing, and also layouts.
voicing because you have to device on a midi channel. layouts because there are too many keys on an alpha to simply output every key as a different note, and then do the layout in the host.
this is where osc is a little easier.

hopefully GP could provide a low level api, that would have the same limitations imposted by daws and mid in general.

I really should have another look in this area… now that daws are much more ‘supportive’ in this area. really Ive got a lot of code that solves most of the issues, the main issue was I ‘overcomplicated’ it a bit in MEC…

1 Like

Actually I’m seeing the same problem on the Alpha — I’ve now done a number of tests to confirm that I am sending the correct key number and color information but I’ve discovered that sometimes, the wrong key gets its color changed.

It’s not a buffer problem. I arranged for calls to occur once per second and got exactly the same results.

However, the problem seems to depend on what values were sent previously.

For example, I have a “ticker” object (implemented in Max and Javascript) that allows me to write “text” to the LEDs. You can send a short text (up to 5 characters) into it and it generates the messages.

I was testing using the name of one of our band members, Happy Rhodes. So I sent H, HA, HAP, HAPP, HAPPY
If you look closely at the images, you’ll see that the first four display perfectly. But as soon as I add the last character, three of the LEDs at the very top of the Alpha are getting turned off

The text display at the bottom is displaying the commands interpreted by the EigenLite program

The first, second and third columns are the color, row, col that are actually sent from my test OSC app. the last two columns are the actual color (integer) and keynumber that are used in the SetLED method call. Note that the last three entries are turning off LEDs but the key numbers are correct.

If anybody has any ideas, I’d really appreciate it ---- so close…

not quite sure whats going on here…

my code just calls alpha2::active_t::impl_t::msg_set_led… there is no internal handling (within eigenlite api)… its just a straight pass thru, from there the eigend code then puts this on a pipe ( aka ring buffer) to pass it to the usb write thread.

for me, Ive never had an issue when using this with MEC, however, I do just set the leds at startup, then thats it.
so there could be an issue there?!

as for possible ‘user error’ , really I cannot think of much…

the only thing that is EXTREMELY important is that you call Eigenharp->process() VERY frequently and regularly… this is designed to be called at ‘control rate’ , so every few milliseconds.
if you don’t then all sorts of things will go wrong :wink:
also important you get your threading correct.

when I wrote the first max external (*) , and also when I moved MEC to various platforms, this was always the source of my woes… basically because if then Eigenharp doesnt get its processing (various heartbeats etc) , it will back off, and reconnect, which means you lose a ton of messages.
… and yeah this includes leds messages… (though, I thought these come back on ‘reconnection’ since alpha2::active_t does track what messages its told to turn on/off.

(*) as I said earlier, Id go look at my max external, as I cannot remember what I had to do to solve this, Ive a feeling I had to move away from timers, as they were not reliable enough??..
but cannot remember, as it was a long time ago, and on a much older max version.

Hmm, how big is that ring buffer - and does it lock properly to protect against overflow? Writing over the beginning of a finite buffer would be an explanation for what I’m seeing… it’s totally reproducible.

If you remember, when I first built your test program, I had just added calls to turn on all LEDs and then turn them off (no OSC even involved at that point) and after the call to turn them off, a few of them were still on.

Isn’t your test code doing that via a thread? I’m not explicitly called that process.

    std::thread t=std::thread(process, &myD);

I basically just took that test code and added an OSC Server (basically the class I implemented for Gig Performer and which has no known issue), and it runs on a completely separate thread so won’t interfere with anything.

I’m not using a Max external with eigenlite in it — I’m just running your test program with OSC added and I send OSC commands into it from my own Max patchers, essentially I just replaced the REST calls that I was using to communicate with the original EigenD with lightweight OSC calls.

I need to clarify this…

I did a quick test for David on the led code … and so tested the alpha and tau… and both base units, so look into this…

its now ‘fixed’, but its not the issue we suspect :laughing:

setLED was absolutely fine !

so the issue remains that the device callback is not really relevant for the Tau, since its simple row/column information is just not enough to be useful … I’ll fix this later.

actually the issue was instead the key callback.
this was incorrect reporting key number for the mode keys…
(simple typo, which as I said, was due to me not being able to test when I wrote it initially !)

this meant if you did something like :

    virtual void key(const char* dev, unsigned long long t, unsigned course, unsigned keynum, bool a, unsigned p, int r, int y) {

     eh_.setLED(dev, course, keynum, a); 

then when you press the mode key, it actually would overlap this onto the main keys again, due keynum being wrong.

if you did eh_.setLED(dev, 1, 3, 1), this actually would set the mode light correctly.

anyway, now the key callback is correct.

Note: this ONLY affected the tau… the alpha/pico, have completely different implementations and as far as I know are absolutely fine.

1 Like

Ive just checked this… (in EigenLite, not mec)
and the tau and alpha behave exactly the same.

roll : up = positive, down = negative
yaw : towards you/right = positive, away from you/left = negative.

can you verify this again…

Right, sry, I remembered it wrong. Looks like it was the Pico. I just tried and get negative roll upwards, and negative yaw towards the right (when holding it facing away from me, as if playing).

EDIT: In my APICallback method in EigenCore, that is. So probably a 2 year old EigenLite,

Sigh – I have tracked down the problem - and it is in a javascript patcher that I have that translates strings into keys so that I can “write” letters on the eigenharp.

Somehow, that patcher seems to think I have 25 rows on my eigenharp :slight_smile: 120/5

The REST API that I was using before I got Mark’s code must have just ignored requests that were outside the keyboard (course) range which is why it used to work fine.

I just changed my app that uses Mark’s EigenLite so that it checks the bounds and all is well.

My apologies for even considering that Mark’s code had a flaw!!!

(By the way, the reason this only seemed to fail when writing “Happy” was because that last Y wanted the extra row to display properly)

1 Like

cool, glad you got it working !

no need to apologise… its all part of development, esp when using a new api, hard to know where issues might be.

ok, just checked… indeed pico is inverted in both roll and yaw !

I reversed, but then realised … who’s to say which is correct?
so, I then needed to check with EigenD about which was right … pico, or alpha/tau…?

and it turns out the PICO was correct …

it should be, according to EigenD (!)

roll - up = negative, down = positive
yaw - towards you = negative, away = positive.

(if you see something different in EigenLite let me know !!!)

in a musical context…

you pull DOWN to pitch bend up…
(which matches most layouts concept of pitch increasing as you go towards the bottom of harp)
push AWAY from you to (e.g) increase brightness of say filter.

its funny, I never noticed when using mec with alpha , Im wondering if perhaps ive inverted it somewhere… or just got used to playing it that way ! (Ive not checked, so dont know the answer here!)

anyway, I recommend @Kai and @David you pull the latest EigenLite which has this fixed, and means now EigenLite is consistent between all harps, and EigenD’s behaviour (as far as I have tested)

@David ,not sure if you ‘compensated’ for this, if so, you need to remove the ‘fix’


Actually, it really depends. For me it’s the opposite.

Consider a guitar - a right-handed person typically holds the fretboard/neck with your left hand. Moving your finger to the “right” will lower the pitch. But when you’re holding the Eigenharp vertically, that “right” becomes “down”