Copy link to clipboard
Copied
Dear AE fellows,
most of us know that method
in_data ->current_time
nicely reads out the position of a time slider.
Now the issue. My plugin has its own win32 window (on top of AE main window) as part of its UI.
A lot of the functionality of the plugin takes place inside this win32 window.
This win32 window needs the position of the time slider at each moment of the plugin usage. The question is: how can I pass this value to it.
The point is, if I don't change the parameters of my plugin (and I don't), no messages in the EffectMain (like PF_Cmd_RENDER, PF_Cmd_USER_CHANGED_PARAM and so on) are triggered.
So in_data->current_time never gets updated(!)
Is it at all possible?
i'd probably go with some shared memory with a mutex instead of a file.
but anyways, idle hook on the plug-in side and a timer on the window side would be the way to go. (imho)
Copy link to clipboard
Copied
AEGP_GetItemCurrentTime
Copy link to clipboard
Copied
Thank you, Shachar,
I wrote a simple function:
A_long time_ae(PF_InData * in_data)
{
AEGP_SuiteHandler suites(in_data->pica_basicP);
A_Time time;
AEGP_ItemH myitem;
suites.ItemSuite8()->AEGP_GetActiveItem(&myitem);
suites.ItemSuite8()->AEGP_GetItemCurrentTime(myitem, &time);
return time.value;
}
However it produces access violation error when hitting suites.ItemSuite8()->AEGP_GetActiveItem(&myitem); line. Do you know what could be the reason for that?
Copy link to clipboard
Copied
during what ae command are you calling this function? is the passed in_data valid? becuase such an error is most likely caused by an invalid pica_basicP, which in turn is cause by an invalid in_data.
Copy link to clipboard
Copied
I was thinking about the same lines too.
To pass in_data I do the following.
I declare a global variable:
PF_InData* in_data_glob;
And then, in my EffectMain function I assign:
in_data_glob = in_data;
I know it looks terrible, but how else could I pass in_data to my win32 LRESULT CALLBACK function?
My win32 window (mainWindow in my notation) starts as a button of AE UI is pushed.
So I start it in HandleEvent function, like this:
if (which_hitP->param_index == SKELETON_BUTTON)
{
std::thread bt(mainWindow, (HINSTANCE)0);
bt.detach();
}
Is there normal way to achieve the result?
Copy link to clipboard
Copied
yeah... that's the issue.
AE passes a pointer for the in_data to the plugin during a call. when the plug-in returns from that call, AE will relesae the memory holding the in_data, so any access to the same in_data pointer at a later time is guaranteed to fail.
furthermore, with the exception of AEGP_CauseIdleRoutinesToBeCalled(), no other callback may be used outside of an AE call span. i.e, your window can't communicate with AE during a window event (unless that window is modal and is ran during the span of an AE call while running on the main UI thread).
so if your window doesn't meet this critirea, you'll need to devise some method of storing a "message" somewhere, and implement some idle hook to check for messages and execute the AE interaction during the idle hook call.
Copy link to clipboard
Copied
Thanks, for an advice Sachar!
Actually, what I'm trying to implement is the synchronous play of animation in my win32 window and in AE (or Ppro) window. That is needed for the designer preview function.
I sometimes think of creating a .txt file with the time and update it every 10th of a second and then my win32 window will read the data from the file every 10th of a second and that's it.
Do you think it could be a viable solution? (Here we need to keep in mind that such a synchonization will be switched on by the user just from time to time)
Copy link to clipboard
Copied
i'd probably go with some shared memory with a mutex instead of a file.
but anyways, idle hook on the plug-in side and a timer on the window side would be the way to go. (imho)
Copy link to clipboard
Copied
Thanks, Sachar!
I'll try to implement this!
Copy link to clipboard
Copied
Dear Shachar,
sorry about continuing this discussion.
I think I'm almost through. But I encountered another issue with
AEGP_GetActiveItem
I need it to get triggered whenever I move my slider. I tried to add it to EffectMain. It almost worked. Bu! iIt is triggered whenever I click on the timeline with my mouse. If I simply pull the time slider, EffectMain never called,
Is it somehow possible to trigger the calculation of the time slider whenever the user moves it?
So far I've found none.
Copy link to clipboard
Copied
not as far as i know. idle hook would not be immediate, but it would almost as good as an immediate call.
idle hook is called between 10 and 50 times per second. these are definatley interactive speeds.
Copy link to clipboard
Copied
Thanks, Shachar!
Since I never implemented idle hooks may I ask for some short hint?
1. is there some available somple code where I could find the sample implementation of an idle hook?
(I tried to google, but it always refers me to "idle task hook". Does it feel as the correct ref?).
Do I undertsand the logic of implementation correctly?
1. Since I need AEGP_GetActiveItem in any case I suppose I'll insert the code for the hook right into my EffectMain function.
2. Somehow I need my AEGP_GetActiveItem to work constantly for some time duration and to get updated 25 -30 times a second. That means I should somehow make it work continously. That entails that I need to read out and update my in_data->pica_basicP 25-30 times a second (or simply in_data).
3. to achieve this in_data->pica_basicP constant update I need to create this magical hook.
Is it a correct logic?
Is a hook a separate function which intercepts the memory address (or something like this) of in_data->pica_basicP and make it recompute 25-30 times per second?
Copy link to clipboard
Copied
the plan is to call AEGP_GetActiveItem and act on it during idle hook.
here's how to set it up.
create some static data strcuture to pass onto the idle hook function.
struct MyIdleHookData {
SPBasicSuite *pica_basicP;//you'll probably want this...
//add any other bit of info you'd like to use like, say, your global data pointer.
}
during global setup, call:
static MyIdleHookData idleData;
idleData.pica_basicP = in_data->pica_basicP;//fill the rest for the transfered goodies as well.
AEGP_PluginID aegpID;
suites.UtilitySuite6()->AEGP_RegisterWithAEGP(NULL, "some name", &aegpID);
suites.RegisterSuite5()->AEGP_RegisterIdleHook(aegpID, IdleHookFunction, (AEGP_IdleRefcon)&idleData);
that's if for the setup. the idle hook function will now be regularly called.
now for the implementation of the idle hook function:
PF_Err IdleHookFunction(AEGP_GlobalRefcon plugin_refconP, AEGP_IdleRefcon refconP, A_long *max_sleepPL) {
*max_sleepPL = 500;//the max time you'd like before the next idle call, in ms.
MyIdleHookData *idleData = (MyIdleHookData*)refconP;
AEGP_SuiteHandler suites(idleData ->pica_basicP);
//that's it. go nuts with whatever process you'd like to do. call AEGP_GetActiveItem and process it here.
return PF_Err_NONE;
}
Copy link to clipboard
Copied
Shachar, thank you so much for this solution!
I'll report as soon as I make the implementation.
I'm sure, a lot of people benefit from this last post of yours.
Yaroslav.
Copy link to clipboard
Copied
Dear Shachar,
I inserted your code.
It works. At first I was very happy. However, a strange thing is happening. Whenever I move the slider, the slider time parameter updates only when I release mouse button .
The same thing happens when I hit play button. The time slider parameter updates only when I hit pause.
In desperation I actually streamed the result of your IdleHookFunction into a txt file and checked if the value changes when I hit play.
PF_Err IdleHookFunction(AEGP_GlobalRefcon plugin_refconP, AEGP_IdleRefcon refconP, A_long* max_sleepPL) {
*max_sleepPL = 100;//the max time you'd like before the next idle call, in ms.
MyIdleHookData* idleData = (MyIdleHookData*)refconP;
AEGP_SuiteHandler suites(idleData->pica_basicP);
A_Time time;
AEGP_ItemH myitem;
suites.ItemSuite8()->AEGP_GetActiveItem(&myitem);
suites.ItemSuite8()->AEGP_GetItemCurrentTime(myitem, &time);
A_long time0 = time.value;
printToFile(time0);
return PF_Err_NONE;
}
It doesn't (despite the file itself being updated many times a second). Only after I release the time slider from the mouse does the vslue updates. Do I do something wrong?
The way I feed data into my win32 window:
I store the result of IdleHookFunction as a global variable which then is fed into win32 callback function.
Copy link to clipboard
Copied
i checked on my end as well, and i see the same behavior. i also tried using javascript's "app.project.activeItem.time" but it also updates only on mouse up.
i currently can't think of way to get the comp's time that might update during a drag over a cached area.
Copy link to clipboard
Copied
hmmm...
i think a custom comp UI would receive idle and draw calls with the current time stamp even when scrubbing over cached frames. but that would only work if your plug-in is selected, and is the ONLY ONE selected.