Best Way To Display Timer Without Flicker

Just starting out? Need help? Post your questions and find answers here.
bcgreen
User
User
Posts: 33
Joined: Sun Nov 02, 2003 7:33 am
Location: Pullman, WA

Best Way To Display Timer Without Flicker

Post by bcgreen »

So...I'm practicing my skills by writing an mp3 player. My question is: how can I display the elapsed time of a track without flicker? (Either in the status bar or a stringgadget)

I have the display constantly updating when a track is playing, and the only way I've found to somewhat reduce flicker is throwing a Sleep_(20) in there after the update....still get some flicker though. How can I produce a rock solid time display?

Thanks as always,
Bryan
Kale
PureBasic Expert
PureBasic Expert
Posts: 3000
Joined: Fri Apr 25, 2003 6:03 pm
Location: Lincoln, UK
Contact:

Post by Kale »

Can you post some code?
--Kale

Image
Codemonger
Enthusiast
Enthusiast
Posts: 384
Joined: Sat May 24, 2003 8:02 pm
Location: Canada
Contact:

Post by Codemonger »

I use Delay(10) sometimes, works good. But yeah, some code would really help out. I imagine Delay() is the same command as sleep_() .
<br>"I deliver Justice, not Mercy"

    - Codemonger, 2004 A.D.
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

You should use the delay only if no other events occured
(WindowEvent() = 0) Otherwise, there will be a delay between each
event like drawing and such, and that causes the flickering.

Timo
quidquid Latine dictum sit altum videtur
bcgreen
User
User
Posts: 33
Joined: Sun Nov 02, 2003 7:33 am
Location: Pullman, WA

Post by bcgreen »

Well, here's my main loop:

Code: Select all

Repeat
 
  event = WindowEvent()
  
  Select event
    Case #PB_EventGadget
      Select EventGadgetID()
        Case #mp3list
          SelectElement(tracks(), GetGadgetState(#mp3list))
          filename$ = tracks()
              Mci("Close thesound")
              Mci("Open " + Chr(34) + filename$ + Chr(34) + " alias thesound")
              Mci("Play thesound from 1 notify")
        Case #browseButton
            filedir$ = PathRequester("Select mp3 Directory:", "")
            If filedir$
              ExamineDirectory(1, filedir$, "*.mp3")
              ClearList(tracks())
              While NextDirectoryEntry()
                AddElement(tracks())
                fullname$ = filedir$ + DirectoryEntryName()
                tracks() = fullname$: OnErrorResume()
                parsemp3(fullname$)
                mpi.MP3Info
                GetMP3Info(fullname$, @mpi)
                mpisec$ = Str(mpi\filelength/1000)
                theminutes$ = Str(Val(mpisec$)/60)
                theseconds$ = Str(Val(mpisec$) - Val(theminutes$)*60):If Val(theseconds$) < 10: theseconds$ = "0" + theseconds$:EndIf
                AddGadgetItem(#mp3list, -1, artist$ + Chr(10) + song$ + Chr(10) + album$ + Chr(10) + theminutes$ + ":" + theseconds$)
              Wend
            EndIf
        Case #playButton
          If playtoggle = 1
            Mci("Resume thesound")
            playtoggle = 0
          Else
            Mci("Pause thesound")
            playtoggle = 1
          EndIf
      EndSelect
  Case 0
      Mci("status thesound position")
      seconds$ = Str(Val(MciResponse$)/1000)
      min$ = Str(Val(seconds$)/60)
      If Val(min$) < 10
        min$ = "0" + min$
      EndIf
      sec$ = Str(Val(seconds$) - (Val(min$) * 60))
      If Val(sec$) < 10
        sec$ = "0" + sec$
      EndIf
      StatusBarText(99, 0, "Current Track: " + min$ + ":" + sec$):Sleep_(20)    
  EndSelect
  
Until event = #PB_EventCloseWindow
GlobalFree_(*buffer)
End
So basically, I'm writing the current position of the file to the statusbar whenever there is idle time (When WindowEvent() = 0) and slapping in a slight delay to cut down the flicker, although there still is some annoying flicker....

Thanks!
Bryan
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Post by fsw »

Don't have time to look at your code deeply but had you time to look at this:

viewtopic.php?t=8261

there is a TextGadget which does not flicker... at least on my machine
Froggerprogger
Enthusiast
Enthusiast
Posts: 423
Joined: Fri Apr 25, 2003 5:22 pm
Contact:

Post by Froggerprogger »

It is just too often updated.
When WindowEvent is 0, the statusbar is updated and then immediately the loop restarts. So (without an delay) it is updated hundreds of times per second. But a delay won't help here, either.
You could put an elapsed time check around your case 0 - code.
Something like this:

Code: Select all

Case 0
  If GetTickCount_() - act_time >= 500
    act_time = GetTickCount_()
    ;... your statusbarupdatecode
  Endif
%1>>1+1*1/1-1!1|1&1<<$1=1
bcgreen
User
User
Posts: 33
Joined: Sun Nov 02, 2003 7:33 am
Location: Pullman, WA

Post by bcgreen »

Cool! Thanks for the snippet. I'll give it a try....

Bryan
AngelSoul
User
User
Posts: 55
Joined: Tue Jul 29, 2003 9:16 am
Location: Canada

Post by AngelSoul »

There is also another method to avoid flickering without having to put delays in your code.

Here's an example:

Code: Select all

OpenWindow(0,50,50,200,30,#PB_Window_ScreenCentered + #PB_Window_MinimizeGadget,"A Window...")
CreateStatusBar(0,WindowID())

Repeat
ww=WindowEvent()
If Date()<>lastdate
   a$=Str(Date())
   StatusBarText(0,0,a$)
   lastdate=Date()
EndIf   


Delay(1)
Until ww=#PB_Event_CloseWindow
Instead of displaying hundreds of times in a second, it'll only display once every second. You can do the same with your sec$ and min$ variables.

Each time you'll display the elapsed time, store those sec and min variables to other temporary values.

Now when the time comes to display the time, put a condition such as:

If min$<>lastmin$ or sec$<>lastsec$
;put what you want to display
lastmin$=min
lastsec$=sec$
EndIf

That way you'll avoid putting unnecessary delays.
Hope this helps.
AMD 1.8 - 512mb - ATI All-In-Wonder Radeon 9000 pro - W2k Pro
BASIC programmers never die, they just return without gosub.
Codemonger
Enthusiast
Enthusiast
Posts: 384
Joined: Sat May 24, 2003 8:02 pm
Location: Canada
Contact:

Post by Codemonger »

That is definately a more accurate way, only update when needed.
<br>"I deliver Justice, not Mercy"

    - Codemonger, 2004 A.D.
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

The correct way to handle an WindowEvent() loop is something like that:

Code: Select all


Repeat
  Event = WindowEvent()

  If Event  ; An event was in the queue so process it
    ....
  Else  
    Delay(1) ; No Event, let the others apps get some CPU time too !
  EndIf
Until Event = #PB_Event_CloseWindow
Why the Delay shouldn't be put after each events ? because when lot of events will come (like refresh, gadgets updates etc..) the apps will wait 20 ms (on windows at least) between each events. So the delay need to be put when no events are recieved. Another (API) way is to use a timer and stick which WaitWindowEvent().

Ok, I will put it in the docs :wink:
AngelSoul
User
User
Posts: 55
Joined: Tue Jul 29, 2003 9:16 am
Location: Canada

Post by AngelSoul »

Cool! A great way to properly optimize your loop.

Haven't thought of that :>
AMD 1.8 - 512mb - ATI All-In-Wonder Radeon 9000 pro - W2k Pro
BASIC programmers never die, they just return without gosub.
bcgreen
User
User
Posts: 33
Joined: Sun Nov 02, 2003 7:33 am
Location: Pullman, WA

Post by bcgreen »

Thanks AngelSoul! That's a great solution...

Bryan
Post Reply