Articles

  • The song loader does more than search for recognised file extensions.

    When OutFox finds a song folder, it also has to decide which parser should handle it. That becomes more complicated when several formats share extensions, tags or structures that have changed over time.

    One of the more expensive examples involved Pump content.

    OutFox supports Pump-specific formats and behaviour, including older content stored in SSC files. Because of that history, the loader could treat some ordinary SSC files as possible Pump charts and send them through additional checks before eventually returning to the normal SSC path.

    The #VERSION:0.81 marker was one of the signals involved, but that marker alone is not enough to prove that a chart contains Pump data.

    Across a large library, those false matches added up.

    We have now made that detection more precise. Files using the dedicated PIU format still go directly to the Pump parser. SSC files can also be identified as Pump content when they contain clearer evidence, such as Pump step types or explicit format markers.

    Normal SSC files no longer need to pass through the more expensive Pump checks based on one broad signal alone.

    On our 3,722-song test library, this reduced one loading run from 677.246704 seconds to 511.741608 seconds.

    That is still far slower than we want, but the result confirmed that format detection was responsible for a meaningful part of the loading time.

    The wider loader work is now applying the same approach elsewhere. Parsers should be checked when the files provide a reasonable reason to check them, rather than asking every possible parser to inspect every folder.

    Compatibility remains the priority.

    We are not narrowing support or abandoning unusual content. Older Pump charts and other formats still need to be recognised correctly. The aim is to reach the correct parser with less repeated work along the way.

    This change has removed one large source of unnecessary parsing, and it gives us a clearer direction for the remaining loader work.

  • This work started with a number we could no longer ignore.

    One of our older benchmarks recorded 3,902 songs taking 791.658415 seconds to load. That is more than thirteen minutes.

    Our current test library is slightly smaller at 3,722 songs, but early measurements were still showing a startup time of 677.246704 seconds.

    Clearly, this was not a case of shaving a little time off the loading screen.

    OutFox has to support libraries built up over many years. That can include several chart formats, converted packs, edits, autogen content, courses, keysounds, banners, jackets, videos and folders that do not always follow the structure the engine expects.

    The loader has gradually learned how to deal with all of that.

    When it finds a song folder, it may need to identify the format, choose a parser, check existing cache data, locate media, rebuild missing information and apply compatibility rules carried forward from older versions of StepMania.

    A lot of that work is necessary.

    Some of it was also being repeated.

    StillRiver allowed us to separate the different parts of startup and see where the time was actually going. Storage speed was only part of the picture. Parsing, cache handling, media checks, file probing and repeated data conversion were all contributing to the delay.

    That gave us something more useful than a single startup time.

    We could see which parts of the loader were doing real compatibility work, which were acting as old safety checks, and which were repeating work that had already been completed elsewhere.

    We are not replacing the entire loader in one sweep.

    There is too much unusual and historical content depending on it, and a faster loader is not useful if songs disappear, charts change or theme-visible information comes back differently.

    Instead, we are measuring each stage and removing unnecessary work while checking that the same library still produces the same usable result.

    The goal is straightforward: large collections should not take several minutes to become playable simply because the engine is checking the same information more than once.

    This is still ongoing work, but we now have a clear baseline and a much better view of where that startup time is being spent.

    That gives us somewhere useful to begin.

  • Replacing RageSound does not mean every old audio interface can disappear at the same time.

    SereneAudio now handles the main audio paths we have qualified, but parts of the engine still call older RageSound methods and objects. Themes, Lua scripts, editor tools, gameplay systems and older content may all depend on those interfaces, even when RageSound is no longer doing the work underneath them.

    Removing those interfaces too early would make the code look cleaner, but it could also break content that currently works.

    We are therefore retiring them in stages, with the old output drivers are no longer used on the SereneAudio routes we have tested. Normal playback, mixing and device output can now run through the new system without RageSound controlling the result.

    What remains is mostly the older surface around that work.

    Some of those calls are straightforward to replace, such as menu sounds and other small interface effects. Others need more care. Music playback, editor behaviour, assist sounds and keysound systems all have wider consequences if their behaviour changes.

    AutoKeysounds and live keysound banks are especially sensitive. Older BMS, PMS and other keysound-heavy content can rely on behaviour that is not obvious from the modern code path alone. Those systems need to be tested properly before their remaining RageSound dependencies are removed.

    The work is therefore being handled one route at a time, slowly, moving each caller to SereneAudio, tested against the existing behaviour, and checked with the content and platforms it affects. Once nothing relies on the older path, that part of RageSound can be removed safely.

    This takes longer than deleting the old classes in one pass, but it avoids making players, theme authors and chart creators absorb the cost of the rewrite.

    OutFox supports a large amount of content built across different versions of StepMania and several rhythm-game communities. The internals can change, but the behaviour people rely on should remain unless there is a clear reason to change it.

    SereneAudio is now doing the real work in our playback and delivery.

    The remaining job is to move the last callers across without breaking the history they still support.

  • With the newer audio and timing paths settling into place, we have started looking more closely at the work still being driven by the gameplay frame loop.

    Over the years, several responsibilities accumulated around the code that tracks notes crossing rows. That path now touches holds, checkpoints, assist sounds, misses, theme messages and cabinet lighting, even though those events do not all need to be checked or triggered every time a frame is drawn.

    This can be difficult to spot during normal play. Each individual operation is small, and the engine still produces the expected result. The problem becomes clearer when the same work is repeated hundreds or thousands of times simply because the frame loop continues to run.

    We have added StillRiver measurements around these row and gameplay-window paths so we can see what is happening before changing their behaviour.

    The aim is not to pull the whole system apart at once. Some of this code controls gameplay behaviour that has existed for many years, across different modes and themes. Changing too much in one pass would make it harder to tell whether a fault came from the original behaviour or from the rewrite.

    The first adjustment has been made to gameplay-side lighting updates.

    Those updates are now limited to a steady 60 Hz instead of running at the full gameplay frame rate. The existing global lighting option is unchanged, and the lower-level lights manager has been left alone. This only prevents the gameplay path from asking for the same lighting work more often than it can usefully change.

    It is a deliberately small change, but it gives us a clean result to measure before moving further into the row-processing code.

    The longer-term work is to separate actions that currently happen together simply because they share an old update path. Row crossings should happen when the song reaches them. Input work should happen when an input arrives. Lighting should update when a lighting event is due. Presentation can continue to follow the frame loop.

    StillRiver is helping us identify those boundaries without guessing or rewriting working behaviour for the sake of tidier code.

    There is more to untangle here, but the first unnecessary work has now been removed without changing scoring, chart timing or input handling.

  • Recent SereneIO testing has focused on something more important than whether a button press reaches the game.

    We also need to know when it happened.

    Older input paths often record an event when the engine processes it. That is not always the same moment the player pressed the button. If an event waits for the next frame or polling cycle, the timestamp can describe when OutFox noticed it rather than when the device produced it.

    For ordinary menu input, that difference may not matter much, but for gameplay timing, it does.

    SereneIO is being built so that OutFox can keep track of where an input timestamp came from. Some backends provide their own event timing, while others rely on callbacks, polling or compatibility paths with less precise information.

    Those routes can all remain useful, but they should not all be treated as though they provide the same evidence.

    During testing, we found that some older input paths were still reaching the engine without enough information about how their timing had been captured. The inputs worked, but we could not use them to support stronger timing claims until that provenance was clear.

    That does not mean those devices or drivers are being removed.

    OutFox supports keyboards, game controllers, dance pads, MIDI equipment, arcade I/O and a wide range of older hardware. Some of those systems need compatibility routes, and keeping them working remains important.

    The aim is to distinguish those routes honestly.

    Where a backend provides a reliable timestamp, SereneIO can preserve and use it. Where the engine has to fall back to polling or older behaviour, that path can remain available without pretending it offers the same timing certainty.

    This also gives us a clearer way to test specialist hardware. Rather than assuming every controller behaves alike, we can look at how each input was captured and decide whether that route is suitable for normal play, compatibility support or more demanding timing use.

    For players, the result should remain simple, presses should arrive reliably, and judgement should reflect when they happened as closely as the hardware and operating system allow.

    For us, the important part is knowing which input paths can support that claim, and which ones still need more work.