Slider for scrolling through frames of a video in Igor 7

Hi all,

I am working on a piece of code to display frames of a video (e.g. a 3D Wave) and scroll through the frames of the video using a slider. On top of displaying the frames, I want to also do some on-line analysis on a given frame.

I realized that my code that was working fine on Igor 6.37 had issues on Igor 7: Slowly dragging the slider would only occasionally update the image and the interface would feel quite unresponsive. A strategically(?) placed DoUpdate resolved this. However, now when I stop dragging the slider (after having it dragged back and forth for a few seconds), the program freezes up for a few seconds. It seems that Igor still works on a queue of instructions at that time, but the graph is not updated any more.

I'd appreciate insights in how I can resolve this. This only occurs on Igor 7.

Here is a minimal working example:
#pragma rtGlobals=3     // Use modern global access method and strict wave access.

// Minimal example:
// genData()
// show()
// Then drag slider

Function Show()
    Wave data
   
    Matrixop/O frame = data[][][0]
    NewImage/N=win frame
    controlbar 50
    SetWindow win hook(myhook) = hook
    slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
End


Function gendata()
    Make/O/N=(512,256, 100) data
    data = Gauss(x,z,3, y, z, 3)
End


Function updateframe()
    Wave data
    Controlinfo sld
    Variable value = v_value
    Matrixop/O frame = data[][][value]
   
    //Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
    Make/O/N=(500,1000)/FREE tmp
    tmp = p*q
   
    doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
    //Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End


Function hook(s)
    STRUCT WMWinHookStruct &s

    Variable hookResult = 0

    print "HOOK"

    switch(s.eventCode)
        //The real code also contains some hooks for working with the displayed data
    endswitch

    return hookResult
End


Function ActionProcName(sa) : SliderControl
    STRUCT WMSliderAction &sa
   
    print "SLD"

    sa.blockReentry=1
    if(sa.eventcode == 9)
        updateFrame()
    endif
End
Nice MWE!

It does work here with •print IgorInfo(0) IGORVERS:7.09;BUILD:31798;IGORKIND:pro64 also when I remove the DoUpdate.

The controlinfo call is superfluous as WMSliderAction has a curval member.
Same here. Runs without freezing.
DoUpdate helps a little for more frequent updates during sliding.

Does your actual hook-code cover the situation of nested calls?

HJ
So none of you can reproduce this? This is weird.

I consistently get the same laggy response on 7.08 32-bit, 7.08 64-bit and also on the latest nightly
print IgorInfo(0)
 IGORVERS:7.09;BUILD:31828;IGORKIND:pro64

All on a Mac.

Maybe I should clarify how I get it to reproduce the behavior: Click and drag the slider around for a few seconds, the longer the worse the lag gets. During dragging, the Console expectedly gets filled with the messages "HOOK" and "SLD". After I then let go of the mouse button, the image stops updating, but the console still keeps displaying additional lines of "HOOK and "SLD".


Also thanks for pointing out the superfluous ControlInfo. I should change that in the real code.


The actual hook code doesn't handle the event of nested calls. I doubt this is the reason for the behavior I'm seeing though as the minimal example with a hook that doesn't do much except print "HOOK" still can reproduce the weirdness. Also, I get the same even when I disable the hook function.
2000 HOOK/SLD pairs with held mouse button and no freezing.
Win7-64bit, 16GB RAM (6GB used), i7-2630QM @ 2GHz

Cannot try on Mac.
HJ
Tried it on my Mac

No issues.

MacBook Pro (Retina, 13-inch, Mid 2014)
2.6 GHz Intel Core i5
Intel Iris 1536 MB

Andy
Thank you all for reporting. It really appears that I'm the only one who is seeing this. Just to convince myself I'm not completely crazy, I recorded a screen cap of the behavior without DoUpdate (choppy) and with DoUpdate (keeps doing something after it's supposed to be done):

https://www.dropbox.com/s/tgxk298orxeezxq/with%20DoUpdate.mov?dl=0

https://www.dropbox.com/s/9rtvfugpagwf5ho/without%20DoUpdate.mov?dl=0

The system is OsX 10.13.4 (iMac i5 2017) with Igor-64 7.08.
I see what you originally reported using IP7 and 8 on Macintosh (haven't tried on Windows).

I agree that without the DoUpdate command, the image isn't super responsive (though in my opinion it still looks pretty responsive).

I think the issue you are seeing with the "freeze" is really an artifact of your use of print statements. Printing to the history in Igor 7+ can be slower than Igor 6, and hundreds or thousands of print statements in a row can slow down the rest of your code.

I replaced your print statements with a ValDisplay in your control bar that changes color when the slider action procedure executes. Now, if I move the slider back and forth for a while and stop, the LED continues to flash for maybe 1/2 a second.

Using Igor 8, I think the update speed without the DoUpdate command is a little better, for what it's worth.

// Minimal example:
// genData()
// show()
// Then drag slider
 
Function Show()
    Wave data
 
    Matrixop/O frame = data[][][0]
    NewImage/N=win frame
    controlbar 50
    SetWindow win hook(myhook) = hook
    slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
    ValDisplay valdisp0,pos={341.00,1.00},size={20.00,20.00},bodyWidth=20
    ValDisplay valdisp0,limits={0,1,0.5},barmisc={0,0},mode= 2
    ValDisplay valdisp0,value= #"doingActionProc"
End
 
 
Function gendata()
    Make/O/N=(512,256, 100) data
    data = Gauss(x,z,3, y, z, 3)
    Variable/G doingActionProc
End
 
 
Function updateframe()
    Wave data
    Controlinfo sld
    Variable value = v_value
    Matrixop/O frame = data[][][value]
 
    //Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
    Make/O/N=(500,1000)/FREE tmp
    tmp = p*q
 
    doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
    //Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End
 
 
Function hook(s)
    STRUCT WMWinHookStruct &s
 
    Variable hookResult = 0
 
    //print "HOOK"
 
    switch(s.eventCode)
        //The real code also contains some hooks for working with the displayed data
    endswitch
 
    return hookResult
End
 
 
Function ActionProcName(sa) : SliderControl
    STRUCT WMSliderAction &sa
 
    NVAR doingActionProc
   
    doingActionProc = !doingActionProc
   
    //print "SLD"
 
    sa.blockReentry=1
    if(sa.eventcode & 0x01) // value set
        updateFrame()
    endif
End
Thanks for your comments, aclight. I don't think that it is only an artifact of the print statement though. I can make your example produce the same problem by making the expensive dummy function run longer, e.g. Make/O/N=(3000,1000)/FREE tmp, without the use of print.

It seems that the sa.blockReentry=1 in 6.3 prevented the build up of an execution queue.

Nevertheless, in case I don't pass the slider value as a parameter from ActionProcName() to updateframe() but instead use Controlinfo in updateframe(), I can use the following workaround to prevent the lockup:

// Minimal example:
// genData()
// show()
// Then drag slider
 
Function Show()
    Wave data
 
    Matrixop/O frame = data[][][0]
    NewImage/N=win frame
    controlbar 50
    SetWindow win hook(myhook) = hook
    slider sld, limits={0,99,1}, size={300,20},vert=0,proc=ActionProcName
    ValDisplay valdisp0,pos={341.00,1.00},size={20.00,20.00},bodyWidth=20
    ValDisplay valdisp0,limits={0,1,0.5},barmisc={0,0},mode= 2
    ValDisplay valdisp0,value= #"doingActionProc"
End
 
 
Function gendata()
    Make/O/N=(512,256, 100) data
    data = Gauss(x,z,3, y, z, 3)
    Variable/G doingActionProc
    Variable/G lastslidervalue = 0
End
 
 
Function updateframe()
    NVAR lastSliderValue

    Wave data
    Controlinfo sld
    if(v_value == lastslidervalue)
        print "BLOCKED"
        return NaN
    endif
    lastslidervalue = v_value

    Matrixop/O frame = data[][][v_value]
 
    //Some dummy function to simulate a lengthy calculation that I want do do after drawing the frame
    Make/O/N=(3000,1000)/FREE tmp
    tmp = p*q
 
    doupdate //<— This seems to be needed in Igor 7 to make the image update responsive
    //Remove this: Updates become very slow. Have it present: Igor locks up for a few seconds after dragging the slider back and forth for a while
End
 
 
Function hook(s)
    STRUCT WMWinHookStruct &s
 
    Variable hookResult = 0

    //switch here etc.

    return hookResult
End
 
 
Function ActionProcName(sa) : SliderControl
    STRUCT WMSliderAction &sa
 
    NVAR doingActionProc
 
    doingActionProc = !doingActionProc
 
    sa.blockReentry=1
    if(sa.eventcode & 2^0)  // value set
        updateFrame()
    endif
End


I finally paid attention to this thread...

For Igor 7, re-entry is strictly controlled, so you will never see that the action procedure is called while it is already running. This was a potential problem in Igor 6.

But Igor 7 will add an event to the action queue while a previous call is running. That is why you saw a string of calls happening after you released the mouse after moving the slider around manically. I added a debugging statement in my development Igor that showed that I had at one point 12 calls waiting in the queue!

Your method for avoiding calls after the mouse is released is quite clever.

Looking at the source code (I have an advantage you don't have :) the blockReentry member works by preventing queueing of further events while the action procedure is running. Well, that's clearly what was intended, but it doesn't work- it searches the event queue for a queued action that has blockReentry set, and doesn't queue another if it finds it. Unfortunately, the currently running action has already been dequeued, so it is never found.

I made an experimental change so that the currently running queue is also searched. That, indeed, results in no extra calls being queued, and probably fixes your problem. But I'm hesitant to put that change into a shipping version of Igor- from the documentation:

Because of architectural differences, reentry occurs on Macintosh only in Igor6 and does not occur at all in Igor7 or later. Because reentry may be affected by internal changes in Igor or by operating system changes, it may reappear as an issue in the future.

That makes it evident that the blockReentry member is truly meant to prevent reentry, not multiple queued events.

I will think about the right thing to do...

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

In reply to by johnweeks

John,

Thanks for the helpful description of reentry and blockReentry in IP6 and 7.

Could you provide an update on reentry and blockRentry in IP8?

Thank you

Apologies for missing the original thread. 

Using MatrixOP to extract the frame is nice but may not be necessary.  If you display a 3D wave as an image you can call from your slider procedure:

ModifyImage imageName plane=n

This will change the display without using MatrixOP.  I have not tested this against the code suggested here but it may be worth the trouble.

 

A.G.

Thanks for the tip, A.G.

Unfortunately, my case is a little bit different and I had left that part out in the MWE. I'm actually generating the displayed frames on the fly while the slider is dragged. I first realized that something was different in IP 7 when I started adding code to the generation routine that made it run slower.

In any case, I'm looking forward to a future solution that doesn't require workarounds. For the moment, the hack still works though.