Willicious 8 Posted May 26 (edited) 2 hours ago, Pat Foley said: What does the SetInfo do on the TV.onclick? It displays the information for the currently-selected tree node within the level select menu's display area. But, this isn't the issue; the issue is that there is a delay between clicking and SetInfo being called. So, whatever SetInfo does, it can't possibly be responsible for the delay. 2 hours ago, Pat Foley said: I populate my treeview childnodes by finding all the menuitems at startup. Then assign the menuitems onclick to the TV. The TV then follows the menu settings. This sounds like it might be helpful for keeping the treeview snappy, but does it cause slower loading times initially? 2 hours ago, Pat Foley said: How is the game paused? is it ctrl- C? In the future pause the game not the IDE, insert a breakpoint, and restart the game. The IDE will then pause at breakpoint. To be sure I understand: do you mean pause in-game, or pause the menu? I'm not sure how to pause the menu, but the game has a "P" hotkey for pause, which is handy for debugging game stuff. The menu is much harder to debug since it can't be "paused", as such. Maybe you mean something else though, in which case this sounds like it might be excellent advice! 👍 1 hour ago, msohn said: If you keep ApplicationIdle commented out and repeat the steps to get the call stack again, what do you get? The call stack screenshot in this reply was always with ApplicationIdle commented out; we were trying to eliminate it at that point. 1 hour ago, Kas Ob. said: 1) Search for every Sleep call in your project from the main thread and remove them, don't use Sleep in main thread not for 1 or even 0 ms, they makes no sense, for background thread it is understandable and useful, but again if the main thread will wait for background thread to finish rendering an animation to paint it then again UI will behave as you described. From what I've seen, sleep is only ever used for between-screen stuff and to relax the CPU (and, in this ApplicationIdle procedure, the only function of which seems to be to update the scroller animation). If I comment out this particular Sleep(1) call, it doesn't seem to make any difference to anything, so maybe it's OK to remove it anyway! When you say "Main thread", it's difficult to know exacly what the main thread is in this project. There are > 46000 lines of code across about 40 separate units! Your advice about not using ApplicationIdle too much seems good, though. Maybe the scroller could be its own procedure. We still need to update it, though. Do you suggest using a TTimer instead for this? 22 minutes ago, msohn said: @Willicious: I managed to get all relevant code from github and have it compiling and running. ... The only bit of a hang I've seen is when I click one of the larger level group nodes - then it takes quite a while because of hundreds of buttons and labels being created on the fly. And another thing which makes this worse, there are many updates, i.e. SetInfo calls, even though the selected tree node hasn't even changed - a simple cache of what was previously selected would improve that situation - or at least remove the Click and DblClick handlers which call SetInfo - any click will rebuild the GUI even though the selected node has not changed. Thanks for taking the time to build and test, appeciate it Yes, the SetInfo call is probably a bit much for the click handlers. The reason I did this is because the node labels (i.e. the names of the levels) don't load when opening a new "tree" - so, for example, clicking on "SuperLemmix Welcome Pack" would open all the nodes for that pack, but the level titles would all be blank until a node was manually selected. I realise that calling SetInfo is overkill for this, but I tried and couldn't find any other way to do it. And yes, definitely, I'd like to cache stuff so SetInfo does the bare minimum. This is a good shout. Not sure where to start with it, though. I will sit down with it at some point and see what's possible. Edited May 26 by Willicious Share this post Link to post
Pat Foley 51 Posted May 26 One. Just load a pre made with TV.LoadFromFile(wellformedTV.txt) and hookup as needed. Two. Your onidle is missing the pausing and userpause Booleans used in other Lemmix repros. So a Pause can not exit the onidle event. 1 Share this post Link to post
msohn 28 Posted May 26 (edited) 26 minutes ago, Willicious said: Yes, the SetInfo call is probably a bit much for the click handlers. The reason I did this is because if I remove them, the node labels (i.e. the names of the levels) don't load when opening a new "tree" (so, for example, clicking on "SuperLemmix Welcome Pack" would open all the nodes for that pack, but the level titles would all be blank until a node was manually selected. I realise that calling SetInfo is overkill for this, but I tried and couldn't find any other way to do it. Yes, I see that now too. SetInfo really does too many things - it not only shows the details about the level/group, it also manages the tree (i.e. LoadNodeLabels) - but only the visible ones, and it does so every time, even if most of the nodes will end up unchanged because they were previously updated. Edit: I see now that it skips nodes with a non-empty text, but that renders it quite useless - I thought the whole point of doing it so often, i.e. in SetInfo, is to be able to react to changes? If there are no changes, when why not fill everything properly in InitializeTreeView? A better place for calling SetInfo might be in OnExpanded - as that is the only place where uninitialised tree nodes become visible (also AFAICS). I made that change (uncommenting the Click and DblClick handlers and adding a SetInfo call in a new Expanded handler) and it seemed to work OK! The whole fInfoForm seems very inefficient to me and it also doesn't really behave very user-friendly (no mouse-wheel support, only the buttons are clickable). The whole thing could be done as an owner drawn listbox with a bit of extra code to react to the "buttons". This will certainly take some effort, but it would improve things a lot since not all x00 entries need a button and two labels being created. Edited May 26 by msohn 1 Share this post Link to post
msohn 28 Posted May 26 @Willicious: have a look at the .patch I attached. That are 2 relatively small changes that improve the situation a lot from what I can see. It caches the group for which the PackTalismanInfo has been generated so it can skip that time-consuming process if the selected group is still the same. And it uses the .OnExpanded handler I mentioned above. SuperLemmixPlayer-18-27-08.patch 1 Share this post Link to post
Kas Ob. 120 Posted May 26 22 minutes ago, Willicious said: Do you suggest using a TTimer instead for this? That depends if you are doing some drawing, updating some visually elements... in other words if the updating the scroller is more than painting already cached images or change position of already ready to draw elements then use a thread to do it, then use the timer to do the paint or the update, but in both cases timer will solve your problem. 25 minutes ago, Willicious said: When you say "Main thread", it's difficult to know exacly what the main thread is in this project. There are > 46000 lines of code across about 40 separate units! Main thread is the first thread in your application the one handed the execution form OS starting the dpr code, and called Application.Run, this one is the only one should handle all your UI (VCL/FMX) and their events, MainThread is a name for specific thread and not some generic terminology. Also keep in mind that your MainThread is the one responsible for any stuttering or slow UI handling, so we need to free it from doing anything expensive or might take long time, its job is answering OS messages (aka user and OS input and your specific requests from the OS)as fast as possible, when that is full filled the UI will be smooth, fast and keep up with screen refresh rate. You could share your CPU usage as it might indicate the problem, is it too much work or too much sleep and wait ? To do that, use Process Explorer from Sysinternals, then double click on your application, in that properties window, take screenshot of two tabs, and another screenshot for the following tabs after some time passed like 1 minute or more: Threads Performance Graph These tabs might help identifying strange or wrong behavior or at least will give an insight of the performance in overall. 1 Share this post Link to post
Willicious 8 Posted May 26 41 minutes ago, msohn said: @Willicious: have a look at the .patch I attached. That are 2 relatively small changes that improve the situation a lot from what I can see. It caches the group for which the PackTalismanInfo has been generated so it can skip that time-consuming process if the selected group is still the same. And it uses the .OnExpanded handler I mentioned above. SuperLemmixPlayer-18-27-08.patch Thanks for this! This is the first time anyone has sent me a .patch, how do I apply it? Share this post Link to post
msohn 28 Posted May 26 1 minute ago, Willicious said: how do I apply it? Are you using a GUI git client? Mine offers to apply patches (I highly recommend https://fork.dev). But after all it's a text file, it's not that difficult to read and understand it, especially since the changes are small and I described what I changed. And then there's also the command line, see https://git-scm.com/docs/git-apply 1 Share this post Link to post
Willicious 8 Posted May 26 16 minutes ago, msohn said: Are you using a GUI git client? Mine offers to apply patches (I highly recommend https://fork.dev). But after all it's a text file, it's not that difficult to read and understand it, especially since the changes are small and I described what I changed. And then there's also the command line, see https://git-scm.com/docs/git-apply I'm using SourceTree. I found the "Apply Patch" option, but when I load the .patch file SourceTree crashes before I can apply it. Not to worry though, I applied the changes manually and it does seem a bit snappier now. The Expanded event handler is a much better place to call SetInfo, for sure. The only issue is that using fLastGroup to store the Talisman info doesn't seem to work. If you click the pack (i.e. to display the Talisman list), then click a level within that pack, then click the pack again, the Talisman list doesn't load a second time. I get what you were trying though; it's things like this which make the program so much more cumbersome than it appears at first glance. At some point I plan to have a really good in-depth look at the Level Select in general. I'm thinking of building a custom screen for it using the existing Menu screen logic. Share this post Link to post
msohn 28 Posted May 26 1 hour ago, Willicious said: The only issue is that using fLastGroup to store the Talisman info doesn't seem to work. Yes I see that now - didn't properly test my changes. Have a look at the attached patch - before exiting, it makes the talisman box now visible. Fixes the issue that you described. SuperLemmixPlayer-21-25-34.patch 1 Share this post Link to post
Willicious 8 Posted May 27 17 hours ago, msohn said: Have a look at the attached patch - before exiting, it makes the talisman box now visible. Fixes the issue that you described. Great! I see what you've done. Thanks for this, much appreciated 🎉 Share this post Link to post
Willicious 8 Posted May 27 20 hours ago, Pat Foley said: One. Just load a pre made with TV.LoadFromFile(wellformedTV.txt) and hookup as needed. When you say "pre-made", does this mean the items have to be pre-loaded, or can this be a blank tree which is populated when loading the program? If the former, then doesn't that mean a lot of manual text editing work for the user? If the latter, how does it differ from/improve on the current stock treeview? Share this post Link to post
Willicious 8 Posted May 27 (edited) 20 hours ago, Kas Ob. said: These tabs might help identifying strange or wrong behavior or at least will give an insight of the performance in overall. Thanks for this! Here are the screenshots: The jump up is when I click the Level Select button in the Main Menu. It currently takes about 2 seconds to open (it also takes about 2 seconds to close as well): This is the Threads tab. Not sure exactly what any of this means, but I'm willing to learn if it will help speed up the program and optimise memory usage: I have the Debug build output a dialog with memory leaks info. I did some stuff in the Level Select screen before closing the program. Here is the output dialog showing memory leaks. I'm not sure exactly how to address these, because I'm not sure what they're pointing to. Is there a way I can get it to output more specific information that points to code areas so I can fix them? Edited May 27 by Willicious Share this post Link to post
Lars Fosdal 1789 Posted May 27 @Willicious A common challenge when updating UI components that have events of their own, is that setting values in the component, will trigger said events, which again trigger your event handlers, which then exec code that changes other UI elements. Do you take steps to ensure that you don't get a flurry of events between different parts of the UI and biz logic when you change data in the components? Share this post Link to post
Pat Foley 51 Posted May 27 55 minutes ago, Willicious said: When you say "pre-made", does this mean the items have to be pre-loaded, or can this be a blank tree which is populated when loading the program? If the former, then doesn't that mean a lot of manual text editing work for the user? If the latter, how does it differ from/improve on the current stock treeview? Pre-make may be a bad 'fork' 😞 Otherwise saving the treeview and and reloading the treeview could allow a game to be restarted at the level the game was when tree was saved. Rather than needing to play the game at lower levels each time starting the game. Loading the game saved at higher level would save the users time. Or does the menu already have this feature? Share this post Link to post
Kas Ob. 120 Posted May 27 59 minutes ago, Willicious said: The jump up is when I click the Level Select button in the Main Menu. It currently takes about 2 seconds to open This indicate long process and from the memory graph there is huge allocation(s), but no CPU spike also no spike in IO, this means the process or the main thread was waiting or sleeping, aka doing nothing. 1 hour ago, Willicious said: While this is concerning, Context Switches at 272k with 3 seconds of User Time, this is too much of thread switching while the code in user mode. See this is my ThunderBird (an old version before switching to Chromium means it is single process) , It was up and running for 6 hours and still doesn't have that much of switching while in CPU cycles used as half of the shown in your screen shot. I asked for 2 different shots to compare with some interval between them, so we can see if these context switches as still happening or stopped after loading the form, and fortunately your screenshot landed on your app main thread, which i didn't explicitly point it to fearing of spending time explaining stuff might not be relevant here, so if you will repost screenshot make sure to select that thread from your EXE. ps: if you will repeat the screenshot then first run Process Explorer as Administrator, i would helpful to see the kernel time. Anyway, and to what i do see: Your application is literally doing nothing, there is no intensive CPU usage at all, but there is two background threads i am concerned about, one from dsound usaualy indicate the directsound is playing or recording, in other words there is an audio operation in work. one from BASS.dll, but not sure about this as i am not familiar with bass, only general and past knowledge, so it might be relevant to the above or might not be. from the above i have a question : Are you playing sound(s) in the background or on mouse movement events ? (are you playing sound effects ?) What ever is the answer, try to stop all audio operation like playing sounds and see how does that impact the responsive of your UI, and please share your finding. One more point : to my knowledge BASS library is fully equipped with background threads handling/playing, so most its operations can be asynchronous, to me your unresponsiveness UI is a symptoms of long synchronous operations called from MainThread, the one that should not be doing much other than handling user input, UI, and essential OS calls/notifications, and of course drawing/updating UI (this drawing is more like slapping already rendered image on a canvas). 1 Share this post Link to post
msohn 28 Posted May 27 2 hours ago, Willicious said: I'm not sure exactly how to address these, because I'm not sure what they're pointing to. Is there a way I can get it to output more specific information that points to code areas so I can fix them? Not with the built-in tools, but here's an excellent summary by Remy of what you need to do: https://stackoverflow.com/a/1130506/386473 I just used exactly that approach and was able to find and fix the memory leaks in like half an hour. I'll try to make a pull request on GitHub as the patch is a bit larger due to spacing when I introduced new try/finally blocks. 1 Share this post Link to post
msohn 28 Posted May 27 I was looking for an excuse to use VTune again 😉 (thanks to Anders map2pdb!) and here's a flame graph of what's going on while the form is shown: (this is without any sounds being played in the background since I don't have BASS dll lying around - and I'm glad I don't) So the Sleep in ApplicationIdle wastes about one third of the total time. And while FormCreate does spend quite some time in InitializeTreeView, half of it is now because the OnExpanded handler is called during it (that's what @Lars Fosdal was hinting at). But in the end most of the time is spent reading and parsing the level info that is spread over hundreds of text files. 1 Share this post Link to post
Anders Melander 1773 Posted May 27 3 hours ago, Willicious said: I'm not sure exactly how to address these, because I'm not sure what they're pointing to. If you still have madExcept installed you can enable leak detection in it, recompile, run, exit and it will produce a nice list where you can double-click each entry and it will take you to the exact source line where the leaked resource was allocated. I just tried with Neolemmix; Run, exit, tons of leaks: 2 hours ago, Kas Ob. said: Context Switches at 272k with 3 seconds of User Time, this is too much of thread switching while the code in user mode. This is the direct result of running the animation loop from Application.OnIdle with Done=False. Replacing it with a timer would solve that problem. 11 minutes ago, msohn said: But in the end most of the time is spent reading and parsing the level info that is spread over hundreds of text files. That problem can probably be "solved" by simply displaying a progress bar while the files are being processed; Users are willing to tolerate quite a lot of delay as long as they know why they are waiting and can see some progress. 1 Share this post Link to post
Willicious 8 Posted May 28 On 5/27/2024 at 2:16 PM, Lars Fosdal said: Do you take steps to ensure that you don't get a flurry of events between different parts of the UI and biz logic when you change data in the components? I'm not sure tbh. The project is many programmers' work, I am the most recent. I have the least experience and am working solo. I wouldn't know exactly what steps have been taken to ensure that the message queue isn't overloaded unnecessarily. On 5/27/2024 at 3:05 PM, Pat Foley said: Otherwise saving the treeview and and reloading the treeview could allow a game to be restarted at the level the game was when tree was saved. Rather than needing to play the game at lower levels each time starting the game. Loading the game saved at higher level would save the users time. Or does the menu already have this feature? It already does this. The user data is saved to a text file and then loaded into the treeview, so it always opens at the last-played (or next unsolved) level (depending on user options). On 5/27/2024 at 3:25 PM, Kas Ob. said: fortunately your screenshot landed on your app main thread, which i didn't explicitly point it to fearing of spending time explaining stuff might not be relevant here, so if you will repost screenshot make sure to select that thread from your EXE. Before I do this, just wanted to make sure that I'll deliberately do the correct thing next time rather than indeliberately. How can I make sure I'm showing the main thread? On 5/27/2024 at 3:25 PM, Kas Ob. said: one from dsound usaualy indicate the directsound is playing or recording, in other words there is an audio operation in work. one from BASS.dll ... Are you playing sound(s) in the background or on mouse movement events ? (are you playing sound effects ?) What ever is the answer, try to stop all audio operation like playing sounds and see how does that impact the responsive of your UI, and please share your finding. ... to my knowledge BASS library is fully equipped with background threads handling/playing, so most its operations can be asynchronous, to me your unresponsiveness UI is a symptoms of long synchronous operations called from MainThread, the one that should not be doing much other than handling user input, UI, and essential OS calls/notifications, and of course drawing/updating UI (this drawing is more like slapping already rendered image on a canvas). The menu screens play short sound effects when buttons are clicked. All sounds are handled through BASS, so... from what you're saying, this shouldn't be causing any issues (if I've understood correctly - i.e. the UI unresponsiveness is due to synchronous rather than asynchronous {i.e. BASS} operations)? It's possible that the main thread is doing more than handling UI. I'll get those screenshots to you once I know what I'm doing. On 5/27/2024 at 3:56 PM, msohn said: I just used exactly that approach and was able to find and fix the memory leaks in like half an hour. I'll try to make a pull request on GitHub as the patch is a bit larger due to spacing when I introduced new try/finally blocks. Got the pull request, thanks for doing this! As I work on this project solo it's great to get help from more experienced devs. And, it's good to know that any memory leaks I see from now on will be because of something I've done (and so can quickly fix myself). On 5/27/2024 at 5:05 PM, msohn said: So the Sleep in ApplicationIdle wastes about one third of the total time. And while FormCreate does spend quite some time in InitializeTreeView, half of it is now because the OnExpanded handler is called during it (that's what @Lars Fosdal was hinting at). But in the end most of the time is spent reading and parsing the level info that is spread over hundreds of text files. OK... so, perhaps I can implement the scroller animation so it isn't handled by ApplicationIdle. Which would be better for time logic, TTimer or GetTickCount? Meanwhile, could caching all level info help? Rather than always parsing the same level info over and over every time Level Select is loaded, SLX could instead load this data from cache and then check for any new additions (something like that, maybe?). The userdata file (the one which stores save data, records, talismans, etc) would still need to be parsed as that will necessarily change each time SLX is run and played. Share this post Link to post
Willicious 8 Posted May 28 (edited) On 5/27/2024 at 5:38 PM, Anders Melander said: This is the direct result of running the animation loop from Application.OnIdle with Done=False. Replacing it with a timer would solve that problem. OK, so a TTimer would be better than using GetTickCount for running the animation (and, of course, handle it in a separate procedure)? On 5/27/2024 at 5:38 PM, Anders Melander said: That problem can probably be "solved" by simply displaying a progress bar while the files are being processed; Users are willing to tolerate quite a lot of delay as long as they know why they are waiting and can see some progress. 💯 Totally agree with this. I've recently implemented visual feedback for several features in both the SLX Player and Editor (status bar, panel hints/messages and progress bars to name a few), so that the user knows that something is happening. With loading levels though, it's probably too quick to warrant a progress bar but slow enough to be noticeable. Edited May 28 by Willicious Share this post Link to post
Willicious 8 Posted May 28 (edited) As an aside, I'm looking at possibly implementing a totally new level select screen which is based on the same look and feel of the existing menu screens. Here's a mockup. This is dreamland at the moment, I only have vague ideas of how I might go about this (and I'd still need to solve the problem of parsing level info): (The row of text "buttons" along the bottom would change according to whether a pack or a level is selected - it wouldn't display both rows at the same time). Also, please excuse the haphazard layout, it's really a basic mockup at the moment. Edited May 28 by Willicious Share this post Link to post
Anders Melander 1773 Posted May 28 1 hour ago, Willicious said: How can I make sure I'm showing the main thread? It's the first in the thread list: 1 hour ago, Willicious said: OK, so a TTimer would be better than using GetTickCount for running the animation (and, of course, handle it in a separate procedure)? No; You do both: Use the timer to trigger the animation. Use GetTickCount to calculate which frame to display. I would probably stop the timer at the start of the OnTimer handler and start it again at the end, in order to avoid a flood of timer messages if the handling is too slow. If you move the animation out of OnIdle, remember to change the OnIdle handler so it sets Done=True (instead of False, like now). This way the OnIdle handler will not get called continuously. Also take care to not do anything in it that will produce windows messages. 1 hour ago, Willicious said: With loading levels though, it's probably too quick to warrant a progress bar but slow enough to be noticeable. If it's almost too fast to warrant a progress bar then simply introduce a tiny delay. You might make the load slightly slower but the user experience might be better. 1 hour ago, Willicious said: (The row of text "buttons" along the bottom would change according to whether a pack or a level is selected - it wouldn't display both rows at the same time). Also, please excuse the haphazard layout, it's really a basic mockup at the moment. Looks good. This might be a bit too advanced for you at the moment, but I would strongly suggest that you make each element (e.g. each button) a layer. It will make the interaction and control of the elements so much easier and perform much better since it utilizes TImage32's built-in repaint optimizer to avoid the current whole-scene repaints. I have a local branch for NeoLemmix where I changed the main menu screen to use layers for the scroller/banner, logo, buttons, etc. but I had to abandon it since working on NeoLemmix was basically just procrastination. Share this post Link to post
Willicious 8 Posted May 28 (edited) 11 minutes ago, Anders Melander said: This might be a bit too advanced for you at the moment Whenever people say anything like this, I have to think: when will it not be too advanced for me? It's either advanced or it isn't. I'm either up to the challenge or I'm not. I'll only know if I go ahead and try it. With that said, allow me to be the first to admit that I am definitely no more than a novice programmer at best, my interest and experience in it is all from a hobbyist point of view. But, take a look at what I've achieved with SuperLemmix over the past year. You might be surprised at what a beginner is capable of given enough determination and some strong goals! Edited May 28 by Willicious 4 Share this post Link to post
Anders Melander 1773 Posted May 28 10 minutes ago, Willicious said: I'll only know if I go ahead and try it. That's the spirit! I must say that given that you're a relative noob (no disrespect; We've all been there 🙂 ) I am pretty impressed with your determination and with what you've done with SuperLemmix. From what I've seen it's not the easiest of projects to work with. 3 1 Share this post Link to post
Kas Ob. 120 Posted May 29 8 hours ago, Willicious said: Whenever people say anything like this, I have to think: when will it not be too advanced for me? It's either advanced or it isn't. I'm either up to the challenge or I'm not. I'll only know if I go ahead and try it. With that said, allow me to be the first to admit that I am definitely no more than a novice programmer at best, my interest and experience in it is all from a hobbyist point of view. But, take a look at what I've achieved with SuperLemmix over the past year. You might be surprised at what a beginner is capable of given enough determination and some strong goals! Well said and well done but this : 10 hours ago, Willicious said: This is freaking beautiful, nice. Yesterday only i downloaded https://github.com/ericlangedijk/Lemmix at last and tried to build it, but it is not for older Delphi. 11 hours ago, Willicious said: How can I make sure I'm showing the main thread? This is tricky sometimes, but in your case it is very easy, in that PE tab there is Starting Address, pointing to the module created the thread, in your application there is only one started form your EXE, while when debugging in the IDE yes most likely it is the first one unless an imported DLL invoked one and the debugger captured it, Delphi Debugger leave the threads sorted as they being seen, while Process Explorer sort them by CPU usage by default, and its sort options doesn't have running time. 11 hours ago, Willicious said: All sounds are handled through BASS, so... from what you're saying, this shouldn't be causing any issues (if I've understood correctly - i.e. the UI unresponsiveness is due to synchronous rather than asynchronous {i.e. BASS} operations)? That is not exactly what i said, i said BASS is capable to do all its operations in asynchronous, but only if told to do so, the documentation clear about threading like this not so special case ( from https://www.un4seen.com/doc/#bass/BASS_ChannelSetSync.html ) Quote The BASS_SYNC_MIXTIME flag (without BASS_SYNC_THREAD) can be used with BASS_SYNC_END or BASS_SYNC_POS/MUSICPOS syncs to implement custom looping, by using BASS_ChannelSetPosition in the callback. A mixtime sync can also be used to make DSP/FX changes at specific points, or change a HMUSIC channel's flags or attributes. The BASS_SYNC_MIXTIME flag can also be useful with a BASS_SYNC_SETPOS sync, to reset DSP states after seeking. But now and reading more of BASS documentation i don't think it is the culprit here, because i am sure you did disable all the sound effect if there is any changes then you would already mentioned that. Now to the most important question 11 hours ago, Willicious said: It's possible that the main thread is doing more than handling UI. Well evidently is not, and your application has one thread (main one) and from PE it is doing nothing, yet it is not responding in time, so what ? This project is half doomed to work on modern OS and that is by design, after reading the readme which is clearly is pointing that the structure based on DOS era application, where you must not let the thread go anywhere except looping over handling UI and draw/update the screen. There is huge misconception in this approach with assuming to be working on modern OS, from what caught my eye the application is abusing ApplicationIdle to process almost everything, like this I want to suggest something might be look stupid and might be in fact a stupid thing considering i can build or debug or investigate this deeper, but please try the following: 1) Make sure there is no Sleep calls at all ! everything single one of them , these you have to replace them with timers in needed 2) The core problem is this class and how it does lose control and regain it, when sleeping or out of execution there is no update and when it is activated it is doing small update step just to go into sleep again, (again and again sleep is the problem) 3) put a timer on where application idle or that TIdle is used and make it call the according "Application_Idle(Sender: TObject; var Done: Boolean)" manually instead of depending on the VCL library to do so, this means disabling the handler or work around it, then though it should at least show some CPU processing and greatly raise your FPS in your case the application UI responsiveness. Sender not used so you can fill it with nil, as for Done don't process it for first test, not sure if it should be useful at all, i mean even if an animation is done drawing and we can't(and must not) disable the timer as we emulating OnIdle so calling again is merely a simple check. 4) put these timers intervals at 1 ms, start there to see how animation are being drawn, tweaking this is most likely needed but lets find and understand the structure and logic first. Share your result with us ! ps: i can't say for sure about this TIdle, but there is something wrong about it and about having Application.OnIdle being assigned in few other places other than that TIdle, so there might be some conflict or miss handling, so try to replace the Idle handlers one by one , start with the working ones, just to understand the effect and side effect. Share this post Link to post