Page 1 of 1
Best Way To Display Timer Without Flicker
Posted: Tue Nov 11, 2003 1:00 am
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
Posted: Tue Nov 11, 2003 1:32 am
by Kale
Can you post some code?
Posted: Tue Nov 11, 2003 2:01 am
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_() .
Posted: Tue Nov 11, 2003 2:33 am
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
Posted: Tue Nov 11, 2003 3:00 am
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
Posted: Tue Nov 11, 2003 4:20 am
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
Posted: Tue Nov 11, 2003 11:36 am
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
Posted: Tue Nov 11, 2003 11:40 pm
by bcgreen
Cool! Thanks for the snippet. I'll give it a try....
Bryan
Posted: Wed Nov 12, 2003 7:51 am
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.
Posted: Wed Nov 12, 2003 7:59 am
by Codemonger
That is definately a more accurate way, only update when needed.
Posted: Wed Nov 12, 2003 10:31 am
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

Posted: Wed Nov 12, 2003 10:50 am
by AngelSoul
Cool! A great way to properly optimize your loop.
Haven't thought of that :>
Posted: Thu Nov 13, 2003 3:35 am
by bcgreen
Thanks AngelSoul! That's a great solution...
Bryan