Page 1 of 1

Monitor Name Bug

Posted: 08 Mar 2017 17:08
by ForestCat
This will take 5 minutes for you to verify. Please help.

I stumbled across this gem while trying to troubleshoot another bug related to the default switch initialization when a template is loaded. That bug first:

1. Load the template in the editor
2. Connect to Lemur
3. Monitor1 shows that firstof(x) is 0, (rather than the monitor default of 120.350) indicating that somehow, this switch has been 'activated', since the script is triggered on Switch1.x 'up' I placed a ctlout() in that script and it IS being sent when the template loads. That's how this started...
4. Monitor2 shows that array1(firstof(x) is 0, which is wrong, since array1 = {'a','b','c','d'}
5. The buttons and monitors work properly otherwise.

That's part1. Can anyone explain this? Why is that script even executed? This DOES NOT happen with pads.

1. Disconnect the editor from the Lemur
2. Change the name of Monitor1 to foo, and Monitor2 to bar
3. In the onPress script, change the names of the monitors accordingly
4. Reconnect the editor to the Lemur

Both monitors now display their default values, 120.350

An anyone explain to me WTF the names of the monitors have to do with how they work??????????????????

For extra credit, change the default values of the two monitors to strings, ie '120.350'

Now they stop updating when the switches are pressed.

Re: Monitor Name Bug

Posted: 09 Mar 2017 21:04
by oldgearguy
some answers. The state of the switch is saved when the project is saved, so whatever switch button was 'on' when saved will be what is restored.
Since Lemur sets the switch to 1 on load, the Monitor1 value reflects this.

Important -- this is happening during the load process.

During the load of a script, not all variables and functions are guaranteed to be defined until the end of the frame where the load took place. So the reference to the array using firstof(x) is usually undefined and you get 0 in that case.

Part 2 is more interesting. It appears that Lemur will only do the above if the name begins with a capital letter (try foo versus Foo).

I can't get the values to 'stick' like you mentioned - mine always change.

The uppercase vs. lowercase may be a key to another problem someone else mentioned. I was close on the script indirection, but I had some weirdness...maybe this is an answer (until the Liine folks declare it a bug and fix it).

Re: Monitor Name Bug

Posted: 09 Mar 2017 22:14
by ForestCat
Thanks, oldgearguy. You've become the last bastion of truth/support on this forum.

"not all variables and functions are guaranteed to be defined"
Oh, the humanity...

So, since I was dead in the water w/ this, I spent most of the day yesterday trying to find out what was going on with this. I stumbled on some of your old threads re: undefined variables at startup.

That, and my own experimentation have led me to conclude that any script triggered 'On Expression up/dn' WILL fire at load time.

I'm not even gonna comment on what the possible logic would be for implementing a strategy like that.

I'm now ripping apart a rather large and complex 99% OnExpression script-driven template to add a check for an init variable == 1 (manually set by a button, since I no longer trust OnLoad for ANYTHING) to EVERY SINGLE 'On Expression' in this template.

The only thing that helps is that most of the time I only trigger on positive-going expressions.

I've been blaming what I thought must have been my shitty coding for the ENORMOUSLY unpredictable initialization behavior of my templates.

I feel slightly better in that regard :lol:

You say you might have a way to call scripts indirectly???????

Re: Monitor Name Bug

Posted: 10 Mar 2017 12:23
by oldgearguy
being a good Lemur programmer is about as useful as being a good accordion player. :D

Note that any/all of my comments are based on testing, observation, and trial and error. I have no special insight into the internals of how Lemur actually works. With that being said -

My understanding is that Lemur works on a frame concept (think of it as time slices in old mainframe terms). The sequence of events of what happens inside a single is not guaranteed (when multiple events are triggered), but the state of the application is guaranteed at the end of the frame. In addition, when Lemur loads an app, the initial frame processing focuses on setting up the environment, instantiating the objects, and executing any scripts marked as "onload". Again - there's a small warning in the manual about variables not guaranteed to be available during the onload sequencing. However, there are side effects in that if the object has a script executing on an expression change, Lemur may trigger that script as it sets the various internal variables (x, z, etc) to the current state.

This thread adds a level of weirdness in that the instantiation/execution of some objects appears to be based on the name/capitalization. I haven't had much free time to play with this theory to see if it holds across all objects and whether variables that are capitalized get instantiated differently (before/after) other ones. It's really weird behavior and I haven't been able to come up with a reason why they'd code that in specially, so there is a non-zero probability that something else is at work here that we missed.

Back in the real world, I've found getting the state of my applications set to a known quantity to be more difficult than anticipated. What I ended up with was using an onload script with a variables declared locally in that script to set up the state of things. I also use a spare MIDI clock as a timer/marker since it can be programmatically started and stopped.

I tend to save my template with all buttons/switches off or in their 0 position and then use a script that gets kicked off by my MIDI clock check *after* the onload script finishes (last thing the script does is start the MIDI clock and I have an "onframe" script watching for that clock and making decisions about what to do based on that. The onframe is a bit tricky in that it can suck up a lot of cycles if it's a big/complex script, but if you use one or two to simply check state and set/unset another variable, it seems to be minimal impact.

Something to ponder (and part of the path I was pursuing for indirect script references) -- you can store a script call in an array: myFuncs = {script1(), script2(), script3()}; and invoke them using myFuncs[0];
However, I was seeing all the functions being executed all the time. It looks like (at least the way I declared it) the variable is set every frame and since they are actual function calls, the functions get called every frame. If I can figure out how to inhibit that behavior, you should be able to create an array of functions and reference them by offsets into the array.

Re: Monitor Name Bug

Posted: 10 Mar 2017 15:04
by ForestCat
being a good Lemur programmer is about as useful as being a good accordion player. :D
I'd argue that playing accordions is more useful, in that there will always be accordions, their continued existence is not contingent upon one company that clearly no longer gives a sh!t. Like you, I have thousands of hours into this. And after each 12 hour day of trying to find out "why doesn't this work?" I question my judgment in continuing down this path. There is the ever present spector of some forced, unwanted (don't get me started) IOS/Android update breaking Lemur forever, and then what? I don't know how much of this will be portable to another environment, which is ironically why I stay with it.
but the state of the application is guaranteed at the end of the frame.
Not in my experience. I could suck up all the 'frame blame', and happily code around it, IF Lemur was actually stable for beat/clock/tempo-based applications when synced to MIDI and played alongside other things synced to the same clock. It is, for me, NOT. When I bought Lemur (for 50 bucks), it was with dreams of it being a one-stop shop to be able to add controls and beat-synced features to my old MIDI capable analog gear. I don't trust it's timing, and now I don't trust it's initialization. I'm not sure what I do trust about it at this point.
It's really weird behavior and I haven't been able to come up with a reason why they'd code that in specially
if I had a dime...
I've found getting the state of my applications set to a known quantity to be more difficult than anticipated.
I'm just gonna code my entire template to DO NOTHING until I press an Init button that sets a flag that EVERY SINGLE SCRIPT CHECKS. It's no more of a hack than some of the other coding transgressions I've been forced to commit to tiptoe around a 'frame-accurate' architecture that isn't. My days of having this thing spit out 'uninitialized' MIDI strings that I DID in fact initialize are DONE.

************************** LIFESAVING TIP FOR ANYONE ELSE PAYING ATTENTION ***********************

For EVERY MIDI/OSC Target in use in your template:
Temporarily, and one at a time, set each target to point to some sort of MIDI and/or OSC Monitor, i.e. MIDI-Ox and/or Bidule running on a PC.
After each change, unload and reload the template and watch the fun on the monitor. You might be amazed to suddenly discover why you've been needing to reboot your downstream MIDI-connected gear and/or apps.

Oh, and one other thing while I'm ranting: I've noticed that 'initialization' behaves DIFFERENTLY when on-load scripts are fired by a change in the editor vs a template load on the device itself.
Hours of fun.

Re: Monitor Name Bug

Posted: 10 Mar 2017 15:43
by oldgearguy
ForestCat wrote:
being a good Lemur programmer is about as useful as being a good accordion player. :D
I'd argue that playing accordions is more useful, in that there will always be accordions, their continued existence is not contingent upon one company that clearly no longer gives a sh!t. Like you, I have thousands of hours into this. And after each 12 hour day of trying to find out "why doesn't this work?" I question my judgment in continuing down this path. There is the ever present spector of some forced, unwanted (don't get me started) IOS/Android update breaking Lemur forever, and then what? I don't know how much of this will be portable to another environment, which is ironically why I stay with it.
but the state of the application is guaranteed at the end of the frame.
Not in my experience. I could suck up all the 'frame blame', and happily code around it, IF Lemur was actually stable for beat/clock/tempo-based applications when synced to MIDI and played alongside other things synced to the same clock. It is, for me, NOT. When I bought Lemur (for 50 bucks), it was with dreams of it being a one-stop shop to be able to add controls and beat-synced features to my old MIDI capable analog gear. I don't trust it's timing, and now I don't trust it's initialization. I'm not sure what I do trust about it at this point.
I've found getting the state of my applications set to a known quantity to be more difficult than anticipated.
I'm just gonna code my entire template to DO NOTHING until I press an Init button that sets a flag that EVERY SINGLE SCRIPT CHECKS. It's no more of a hack than some of the other coding transgressions I've been forced to commit to tiptoe around a 'frame-accurate' architecture that isn't. My days of having this thing spit out 'uninitialized' MIDI strings that I DID in fact initialize are DONE.

************************** LIFESAVING TIP FOR ANYONE ELSE PAYING ATTENTION ***********************

For EVERY MIDI/OSC Target in use in your template:
Temporarily, and one at a time, set each target to point to some sort of MIDI and/or OSC Monitor, i.e. MIDI-Ox and/or Bidule running on a PC.
After each change, unload and reload the template and watch the fun on the monitor. You might be amazed to suddenly discover why you've been needing to reboot your downstream MIDI-connected gear and/or apps.

Oh, and one other thing while I'm ranting: I've noticed that 'initialization' behaves DIFFERENTLY when on-load scripts are fired by a change in the editor vs a template load on the device itself.
Hours of fun.
lol on the accordion reply. Agreed that the time invested is disproportionate to the intended goal. I could have coded up the few apps I've done in C/Python faster and with less headaches, but if you want to use Lemur you don't get a choice. Discovering all the bugs, then figuring out ways to code around them wasted a lot of time and since people have kindly donated $0.00 after downloading/using the templates I've posted, I'm very disinclined to put any more out there or even enhance the ones I have. Even if Liine simply acknowledged issues and posted known problems and possible workarounds (or detailed how it worked internally) it would have saved some time.

I apologize for being overly broad in my statement about known state at the end of a frame. None of that seems to apply when dealing with MIDI clocking and their Step Note/Switch/Slider objects. My guess is that they overlaid the realtime aspect on top of their framework (rather than redesign it to support it) and it shows. Realtime continuous behavior was not an original design goal so the architecture is not set up to support it natively. IMHO the sequencing capabilities of Lemur is a hack on top of the OS, so you get the inconsistent behavior you have observed.

I would not use Lemur for any serious sequencing tasks, based on my initial tests.

When I was developing my editors, I had the gear continuously plugged in to the iPad and was regularly pushing the edited template to the iPad and testing because it *sometimes* worked differently in the editor vs. on the iPad.

My MIDI approach was to turn off MIDI in all of my objects and use scripts exclusively to handle MIDI in and out.

Re: Monitor Name Bug

Posted: 10 Mar 2017 17:33
by midikinetics
You CANNOT reference scripts indirectly...

If you think you've spent time trying to figure out how to do this, I've spent that times ten.
Every few months or so I think to myself "There's GOTTA be a way" and then waste hours trying this and that. It always ends in failure.

You cannot trick Lemur into thinking an expression is a function. The moment you add () after an expression the compiler turns the expression into a one-liner function, to which getexpression and setexpression have no effect.

If you stick a function inside an expression then all this says to the runtime is you are calculating the value. As such, it must execute on every frame in order to work with Lemur's ability to monitor expressions for changes.

The only way to do this is with the way you've already discovered: trigger on expression (typically rising).

If you think that's a hack, then get ready for this one: attach the script to a Canvas object and have it trigger on Redraw.
Then say canvas_refresh(Canvas).

MOH