# Sound recorder `nonemm-recorder` is a separate program (`src/Nonemm.Recorder.App`). It records channels of several audio devices into one Opus file. The code that does the work is in `src/Nonemm.Recorder`, and the window is a thin layer over it. Run it with `./build.sh run --project src/Nonemm.Recorder.App`. ## The file - Ogg Opus, one channel in the file for each row in the list, in list order. - Mapping family 255: each channel is its own mono stream, so a player does not mix them as speakers. A file with one row is plain mono. - 48 kHz, 60 ms frames, complexity 9. The bitrate is for each channel and defaults to 32 kbps, so a file of four rows is about 128 kbps. - A new file is named `recording-yyyyMMdd-HHmmss.opus` in the chosen folder. - Pause leaves no gap: the audio after Resume follows directly on the audio before Pause. ## Channels - Each row picks one channel of one device: `Line In L`, `Line In R`, or just `Microphone` for a mono device. The list of choices is the same in every row. - Output devices are listed as `Speakers (output) L`. They record what that device plays (see "Output devices"). - A device that is not there keeps its row, in red, and writes silence. The program lists the devices every 2 seconds. When the device returns, its channel is recorded from that moment, also during a recording. - Rows cannot be added, removed or changed during a recording, as they would change the channel count of the file. - The headphone button plays that channel, in mono, on the default playback device. If it monitors an output device that is also the default one, it feeds back. ## Configuration One file, written when the window closes: `nonemm-recorder/config.json` in the user's application data folder (`%APPDATA%` on Windows, `~/.config` on Linux). It holds the rows, the bitrate and the folder. Rows of devices that were not connected stay in it. ## Output devices | System | How an output is recorded | Tested | | --- | --- | --- | | Windows | WASAPI loopback of that playback device | no | | Linux | the PulseAudio or PipeWire "Monitor of ..." source | no | Neither was tested on real hardware: the machine this was written on has no sound device. The tests in `tests/Nonemm.Recorder.Tests` use a fake sound system and check the file by decoding it again. On Windows, SoundFlow only loopback-records the default output through its public API. `SoundFlowBackend.MarkLoopback` sets an internal setting by reflection to pick any output, so it is tied to SoundFlow 1.4.2. ## Sound system On Linux the program asks for PulseAudio (PipeWire serves it) and falls back to ALSA only if that fails. The window shows which one is in use, and the reason in red when it is the fallback. ALSA lists sound cards and plugins, not the devices a PipeWire desktop shows, and has no "Monitor of ..." sources. SoundFlow 1.4.2 numbers its backend enum one higher than the miniaudio library it ships, so asking for `PulseAudio` gives ALSA and `Wasapi` gives DirectSound. `SoundFlowBackend.Start` lowers the value by one and checks the result. If a later SoundFlow fixes the numbering, that check fails with a message. ## Timing The devices do not share a clock, so the file is cut by the system clock, not by how much each device delivered. The encoder runs 120 ms behind the clock. A device that delivers too little is padded with zeros. One that delivers too much loses its oldest samples once it is 240 ms ahead.