Open sezero opened 2 years ago
moved to in-memory depacking
This should be considered temporary at best—this is almost certainly going to break depacking on low RAM systems and libxmp should be able to fall back to temporary files (maybe with a xmp_set_player
flag to prevent it or to enable this fallback).
going to break depacking on low RAM systems
and there is that, too..
and libxmp should be able to fall back to temporary files (maybe with a
xmp_set_player
flag to prevent it or to enable this fallback).
Or maybe a configuration option
Or maybe a configuration option
That seems reasonable—I think whether or not the target would be low enough RAM for that to be useful would be known ahead of time. I don't think adding that kind of fallback is particularly urgent, anyway, and could wait until someone complains.
Re: ProWizard, I think it used to unpack to RAM at one point, but I'm not familiar enough. Getting ProWizard to the point where it could output to RAM or RAM+stdio would be a big project. There is output size counting deadcode in many of its unpackers that would be ideal to restore for this (to reserve a buffer up front and/or quickly fall back to stdio). The rest could probably be abstracted by adding pw_write
to replace fwrite
.
With temporary files, there is still a potential portability issue where embedded platforms may require more platform-specific code to determine where temporary files should be stored, or may not have enough writable storage to create the file to begin with.
Another possibility is to allow depackers to provide custom HIO streams, similarly to how gzopen
works in zlib. This would definitely be the most difficult approach, though, as it would require depackers to support partial decompression, and may be slower for loaders that seek backwards often.
For comparison, how much RAM does libxmp usually require for module loading and playback?
With temporary files, there is still a potential portability issue where embedded platforms may require more platform-specific code to determine where temporary files should be stored, or may not have enough writable storage to create the file to begin with.
Another possibility is to allow depackers to provide custom HIO streams, similarly to how
gzopen
works in zlib. This would definitely be the most difficult approach, though, as it would require depackers to support partial decompression, and may be slower for loaders that seek backwards often.
That's a reasonable point—I was thinking of embedded systems with SDKs that already provide tempfile functions, but those are probably a minority. libxmp already has handling for custom temporary file directories and a mkstemp
fallback, but making tempfiles a configuration option like sezero suggested tied to Autoconf detection of mkstemp
(or Win32, which has mkstemp.c) could help.
Due to the complexity of the loader test functions and formats with arbitrary seeking (including S3M and IT!), I think pushing off the responsibility of file IO onto the user might work better than trying to stream to the loaders. This might only work with xmp_load_module_from_callbacks
and would require several extra callbacks, which can't be added without breaking API changes. (xmp_callbacks
already needs a read open callback to support things like MOD/STM/MED2 songs and Startrekker AM configuration files, so adding a tempfile open callback and write callback wouldn't be too out of the question.)
For comparison, how much RAM does libxmp usually require for module loading and playback?
I haven't really instrumented this, but a rough overview from my understanding (theoretically assuming depacking works with xmp_load_module_from_memory
and xmp_load_module_from_callbacks
here, which it doesn't yet):
xmp_load_module_from_memory
, or xmp_load_module_from_callbacks
with RAM.xmp_load_module_*
xmp_load_module_from_callbacks
: the archive handle is closed on success. For callbacks, this is only if close_func
is provided. close_func
can be used as a way to guarantee the initial RAM is freed before proper loading starts, which leaves the loading process at the same RAM overhead as if xmp_load_module_from_memory
was used with an uncompressed module. If this is xmp_load_module_from_memory
, both the compressed and uncompressed buffers will now be consuming RAM.libxmp_prepare_scan
and libxmp_scan_sequences
allocate and shrink some buffers that are fairly irrelevant in size to everything else (~5k max with current module length limitations I think).HIO_HANDLE
handles and buffers are released here.close_func
to xmp_load_module_from_callbacks
, user frees/closes handle here.xmp_start_player
allocates the channel_data
(up to ~100kB worst case for IT) and mixer_voice
(up to 20kB) arrays.With a packed module in the MB size range you'd have to keep the packed file (with the memory and callbacks loaders only, theoretically enabled for depacking), the unpacked file, and all data allocated by the loader in RAM at the same time (which in the case of IT or OggMod XMs, could blow up from sample decoding). I think it would require a fairly low RAM system (<=16MB) to be an issue, but this includes several old/embedded systems libxmp can or may plausibly run on.
I don't know how doable this is. The depackers side mostly (if not wholely?) moved to in-memory depacking, but the whole prowizard suite still relies on this functionality.