# Why no MemoryMappedAudioFormatWriter?

**URL:** <https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787>\
**Category:** Development\
**Created:** [August 27, 2022, 11:05pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787 "2022-08-27T23:05:52Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxpollack](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/maxpollack/32/14473_2.png) [@maxpollack](https://forum.juce.com/u/maxpollack)\
**Post date:** [August 27, 2022, 11:05pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/1 "2022-08-27T23:05:52Z")

</div>

Hi all,

I’m working on an implementation of [real-time audio file streaming I/O](http://www.rossbencina.com/static/writings/File_IO_ACMC2014_Bencina.pdf) 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`](https://github.com/Tracktion/tracktion_engine/blob/f57e110f7982f6611b4f5ec41c1a11880849abcf/modules/tracktion_engine/audio_files/tracktion_AudioFileCache.cpp#L451), but [write to them using a regular `AudioFormatWriter`](https://github.com/Tracktion/tracktion_engine/blob/f57e110f7982f6611b4f5ec41c1a11880849abcf/modules/tracktion_engine/audio_files/tracktion_AudioFileWriter.h)? Why not open a [`MemoryMappedFile`](https://docs.juce.com/master/classMemoryMappedFile.html) with [`AccessMode::readWrite`](https://docs.juce.com/master/classMemoryMappedFile.html#a1fb6563237aaf7bd02f4b30f13b0e2d0a600bfb19741145c6c13280a687797041) 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](https://man7.org/linux/man-pages/man2/mmap.2.html)/[Windows](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea)) it appears that these writes occur more often when [`exclusive = false`](https://docs.juce.com/master/classMemoryMappedFile.html#a210e16a18b078c6df3b506a3f9963fe5) to ensure synchronicity for all readers, but with [`exclusive = true`](https://docs.juce.com/master/classMemoryMappedFile.html#a210e16a18b078c6df3b506a3f9963fe5) 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`](https://docs.juce.com/master/classMemoryMappedFile.html#a210e16a18b078c6df3b506a3f9963fe5), 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?**

---

<div class="post-metadata">

**Author:** ![anon48770766](https://avatars.discourse-cdn.com/v4/letter/a/439d5e/32.png) [@anon48770766](https://forum.juce.com/u/anon48770766)\
**Post date:** [August 29, 2022, 9:19am UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/2 "2022-08-29T09:19:22Z")

</div>

Maybe because the OS doing memory paging can interrupt audio processing during the sync to disk?

---

<div class="post-metadata">

**Author:** ![maxpollack](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/maxpollack/32/14473_2.png) [@maxpollack](https://forum.juce.com/u/maxpollack)\
**Post date:** [August 29, 2022, 8:33pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/3 "2022-08-29T20:33:49Z")

</div>

> [@anon48770766](#):
>
> 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](https://man7.org/linux/man-pages/man2/mmap.2.html)/[Windows](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea))) 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…

---

<div class="post-metadata">

**Author:** ![jellebakker](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/jellebakker/32/17053_2.png) [@jellebakker](https://forum.juce.com/u/jellebakker)\
**Post date:** [May 3, 2023, 10:09am UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/4 "2023-05-03T10:09:34Z")

</div>

@maxpollack did you manage to get any answers on your questions?

I’m in need of a MemoryMappedAudioFormatWriter and I wondered if there is some specific reason for why there is no such class in the JUCE codebase.

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [May 3, 2023, 11:35am UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/5 "2023-05-03T11:35:39Z")

</div>

The advantage of the MemoryMappedReader is the access at random positions.  
For the writer it is expected to write a continuous stream, so MemoryMapping doesn’t seem too plausible to me.  
The other advantage of using a BufferingAudioFormatWriter is, you can freely choose the audio format. The memoryMapped is only available for WAV, last time that I checked.

---

<div class="post-metadata">

**Author:** ![jellebakker](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/jellebakker/32/17053_2.png) [@jellebakker](https://forum.juce.com/u/jellebakker)\
**Post date:** [May 3, 2023, 11:50am UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/6 "2023-05-03T11:50:41Z")

</div>

@daniel

This depends on the use case. Writing at random positions might be desired.  
Actually, In my use case I do want to write to an audio file starting from some offset. Once I start writing, it will be a continuous stream. But, all the JUCE audio file writers start from sample 0, as far as I know.

You suggested BufferingAudioFormatWriter, but I cannot find any class named BufferingAudioFormatWriter in the JUCE doc.

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [May 3, 2023, 12:27pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/7 "2023-05-03T12:27:22Z")

</div>

AFAIK most audio formats are agnostic to any time continuum outside. Sometimes a placement within a context is provided via meta data. But that is often platform dependant or even host dependant.

I think you would have to pad it with silence to be sure it actually fits.

Looking at the API of AudioFormatWriter, there isn’t even a way to modify the position…

> [@jellebakker](#):
>
> You suggested BufferingAudioFormatWriter, but I cannot find any class named BufferingAudioFormatWriter in the JUCE doc.

Apologies, that was from my faulty memory. I meant [AudioFormatWriter::ThreadedWriter](https://docs.juce.com/master/classAudioFormatWriter_1_1ThreadedWriter.html) of course.

---

<div class="post-metadata">

**Author:** ![jellebakker](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/jellebakker/32/17053_2.png) [@jellebakker](https://forum.juce.com/u/jellebakker)\
**Post date:** [May 3, 2023, 12:50pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/8 "2023-05-03T12:50:21Z")

</div>

For my application, I just want to be able to write at a certain sample position (assuming it fits within the existing file size, you can also assume the file contains zero’s). In my case it doesn’t have to be a mapped file. My problem is that there is no JUCE class to write audio to a file at a specific position. It’s possible to read from a specific position, not to write to one.

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [May 3, 2023, 1:04pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/9 "2023-05-03T13:04:12Z")

</div>

Yes, it is not even a matter of MemoryMappedWriter, but audio file writing in general.  
Would make an interesting FR.

My take on it would be, that it takes so much knowledge about the existing audio, that it makes more sense to read the old file and write into a new temp file mixing with the original or finding the correct position or whatever operation your use case needs.

---

<div class="post-metadata">

**Author:** ![maxpollack](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/maxpollack/32/14473_2.png) [@maxpollack](https://forum.juce.com/u/maxpollack)\
**Post date:** [May 3, 2023, 5:43pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/10 "2023-05-03T17:43:51Z")

</div>

To move the write position, could you call [`setPosition`](https://docs.juce.com/master/classOutputStream.html#ae95d7b4edfe5eac6a0913b079684572a) on the `OutputStream*` you pass to the `AudioFormatWriter` constructor? Seems like that method is not guaranteed to succeed but at least it will return `false` if it fails.

> [@jellebakker](#):
>
> @maxpollack did you manage to get any answers on your questions?

No concrete answers, but I suspect the reason has to do with the lack of control over when the paging system decides to flush the memory map to disk. Even with `exclusive=true` the OS can decide to discard a page at any time, triggering a file write… so we can only impose a strict limit on the frequency of file writing using traditional file IO methods.

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [May 3, 2023, 7:01pm UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/11 "2023-05-03T19:01:36Z")

</div>

I don’t think this will work, since you disregard the file header, and for compressed formats it might be impossible to find the correct file position, where a specific sample is written.

---

<div class="post-metadata">

**Author:** ![jellebakker](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/jellebakker/32/17053_2.png) [@jellebakker](https://forum.juce.com/u/jellebakker)\
**Post date:** [May 4, 2023, 9:06am UTC](https://forum.juce.com/t/why-no-memorymappedaudioformatwriter/52787/12 "2023-05-04T09:06:06Z")

</div>

I could indeed call setPosition and do a bit of calculation to find the correct byte position from a sample position. The `MemoryMappedAudioFormatReader ` class has internal helper functions (`sampleToFilePos`, `filePosToSample`, `sampleToPointer`) that take care of this. It would be useful for me if these helper functions could become public functions so that I can use those functions to write to a specific sample position in the file.
