christophhart / HISE

The open source framework for sample based instruments
http://hise.audio
Other
1.04k stars 122 forks source link

(Yuge) Preceding Script Processors cannot reference globals from downstream processors on first initialisation / exported plugin #523

Closed aaronventure closed 5 months ago

aaronventure commented 5 months ago
HiseSnippet 808.3oc6V0saSCCE1tqYhFwPLAO.V8pNwXztMFHlPLVa2TEzsJ5Xh6lbcbWslicThyfpo85vqAuR7F.Gmjtzxp1OAwcjKZy4W+4y4y9jdgZFOJRGhvUNZb.GgenS+wJynlinBEpSKD9QNcoQFdHIU0tiCnQQbODFuv9VE3JkQIO+7c6RkTEimqBgNVKX7OJ7Elbs814CBobOpG+Hg+Tdu4NcXZUSsTGC3YAm5n.J6L5o7CnV2J4fvK11SXzg8MTCOB7YWs239izeUk5+whHw.I2Jz.0GRTpZTyQBoWuI60HDBWtW9Negzc9Sc5J7DWoOuB73DCj7HltFfKcSPpw8.RklBRkSgzxN8Ygh.StEKddRl1bD0XFHkZEU56XmlZkgqLq4SOiuWHHzAjCGRY7ZaUu9pD3mU110UnjBEmLLVwLBshvnR49R8.prErQhLgbpesUbuvsBjvHsjuVPnPYpU8XpLl+FRUxyHsO2tPPMv.Yrh6kttPyLxPBnJtj7VxDnP875YUUqp02pqR.Xj.hDGWKharrhvl.DF.s+ZS.U55OejAKHw8R3urbXngoYoVi50q+hMr4+pMmVcf1vOLKg.PI+oogCmqM6NHTKkPZmm4zE7FBrlJ1e.ObUx41p1UNBc6YoPN2MJDKsfNkiZUGkvbX.OS95jLTVW.d6ycZQMTf2gyzA9EvCMBKDvs3mCGbSYgUbZwiNynCR70OPqrY.W1jXcoIbTaoGI.F3hN1NK5avNAaOWOdxKnhyvWedLb7ObNMgKjR9.R1EWtMwMmIBZddis+em+uuyOmVGbsn1KVRMydWocnPlAnFLSayd4iJRXFO8Pi6wEn0uwKPuqPbYmdBCaz7wXo4fQ6cy+CvX1XmkbZObHmYxAXYm89RQmwbKK+mzwFg5ztTSnvd97fX+9vzVFGVcEb90xAwkrrkT45SN51mq7RD9E7jYrgUFmYrwDiHeJKTeBKk4aGr8fDM.lTIywq.ePAHSZfRNMLcc1GlydBiMaptVfqWz.2nnAtYQC7kEMvsJZfupnA95aOP6mA89Xi1O8XCB0sW6jqRv31JJv.SXqneCpJB6fC

macOS 14.4.1 ebfbd32d1fa3f4d38466ff4609509e7e25b16b0d

Alright, here's the scenario. You have a complex script, decoupled from the interface script. Depending on what happens in the realtime callback, you want to draw things on the interface. A very simple way of doing this is storing whatever's happening in a global variable and accessing that from the Interface script. You get to work, set it up, it works.

Then you export your plugin and it doesn't work. So you open HISE again and, well.. it doesn't work here either. But it just worked! You hit F5 out of habit... it works again!

While you can get it to work in HISE, you cannot get it to work in a compiled plugin, because it only ever runs the init once. Calling startTimer with delay doesn't help.


  1. Make sure HISE is closed.
  2. Open it
  3. Load the snippet
  4. The console should read undefined and loop with a timer
  5. Hit F5 to recompile
  6. It now reads -1

There's a global Event = {} object in the second processor. Then Event.test gets initialized at -1. Even though it's not there at the time HISE runs through the first script, it should be there on subsequent timer calls. But it's not. On that first initialization after starting HISE (or every exported plugin initialization), that first processor will always be returning undefined for the object or any of its properties, even though the object is visible in the table of the second processor. That's because the global objects from downstream only become visible to preceding processors on F5 compilations beyond the first (as globals don't get purged on compile).

This is serious because either it doesn't work as intended and breaks the exported plugin UI functionality if tied to downstream globals, or it encourages impossible models that can never be executed in a compiled plugin.

christoph-hart commented 5 months ago

Hmm, I would consider it as your job to not write something like that. Sure, I could add another guard rail here and try to catch this specific glitch, but it all starts with a very sloppy project layout (Global variable 101: you absolutely must define all global variables in the first place you use it). I can see that stuff that works in HISE but not in a compiled plugin is frustrating, but the necessity of smashing that compile button multiple times in HISE should be hint enough that you're deep in hacky land, population: Aaron.

Now this example fails because the HiseScript compiler decides to cache the property access because the ID property is a compile time constant. Now if you absolutely rely on this project layout, then you need to make the property access in the Interface script a dynamic one by using the []-operator like this:

Console.print(event.test); // undefined, the compiler has tried to resolve the ID at compilation and failed
Console.print(event["test"]); // -1, the engine will evaluate the test property dynamically.
aaronventure commented 5 months ago

Alright, understood. I have already shuffled around my processors and made sure all globals were declared first.

The explanation on how the compiler works with property access is a good one, as well as the tip about dynamic access (which I didn't think of!!). Might wanna put that somewhere in the docs, this is all good info.