I’m working on an implementation of real-time audio file streaming I/O to allow playback and recording of long audio files, and lately I’ve been having a peek at the Tracktion Engine’s code for some guidance…
I’m wondering — Why does TE read from audio files using
MemoryMappedAudioFormatReader, but write to them using a regular
AudioFormatWriter? Why not open a
AccessMode::readWrite and use that memory map for both reading and writing? On the surface it seems like a simpler scheme than writing on a background thread…
Of course with memory maps the OS can also decide to write changes to disk at any time. From a glance at the documentation (UNIX/Windows) it appears that these writes occur more often when
exclusive = false to ensure synchronicity for all readers, but with
exclusive = true writing only occurs when the file is unmapped or when the OS discards the page from memory, which is a potential bottleneck as RAM fills up. But with moderate RAM usage and
exclusive = true, are page discards frequent enough to cause significantly worse performance compared to normal file writing?
TL;DR: Is there a reason why writing to memory mapped files is unsuitable for real-time audio recording?
Maybe because the OS doing memory paging can interrupt audio processing during the sync to disk?
I realize now that my question was poorly worded… I’m not asking whether memory maps are real-time-safe or not — they are certainly not, for exactly the reason you just described. My implementation is buffered, so the memory map is not accessed directly by the audio callback, and I can make the buffer as large as I need to account for any paging- or disk-access-related delays.
My question is about the amortized performance of memory-mapped writing vs normal writing to disk. My understanding is that each individual read and write should be faster with a memory map than with normal file I/O, but unlike with normal file I/O we don’t have strict control over when and how often writing happens, because the OS can flush the page to disk at any time. It seems to me from reading this documentation (UNIX/Windows)) that flushing to disk occurs more frequently with
exclusive = false to keep all the readers in sync, but with
exclusive = true it only occurs on page discards and when the region is unmapped (this is my impression from the documentation, haven’t implemented it yet, could be wrong).
I’m wondering if in practice, with
exclusive = true, those OS-triggered writes are infrequent enough to make memory maps perform comparably to normal file writing for audio recording, across platforms.
Of course the most surefire way to an answer would be to write a
MemoryMappedAudioFormatWriter myself and profile it against an
AudioFormatWriter, I’m just wondering if anyone has been down this road before and can save me from a potential dead end.
And from the conspicuous lack of a
MemoryMappedAudioFormatWriter in JUCE, and the choice to read and write audio using 2 different file I/O methods in Tracktion when the facility for both is in
MemoryMappedFile, I suspect their developers may have run into this problem before…