Run this in a shell and let it run:
arecord -D dmic_sv -c2 -r 48000 -f S32_LE -t wav -V mono -v \
| while :; do dd bs=384000 count=1 iflag=fullblock 2>/dev/null >>output; done
Each dd
will send 1 second of data (48000 samples of 4 bytes (32 bits) times 2 channels, so 384000 bytes) to the output
. The important thing is output
will be opened for appending separately for each dd
. This means when you rm output
or mv output soundfile1.wav
, then the next dd
will write to output
anew, i.e. a new output
will be created.
If mv output soundfile1.wav
happens within a single filesystem, no data will be lost. I mean if you concatenate soundfile1.wav
and the new output
then you will recreate the original stream. This is because renaming (or even deleting) a file does not bother a process that has already opened the file.
Moving to another filesystem is in fact equivalent to cp
+unlink
. In this case it may happen some dd
adds to output
between cp
and unlink
and this chunk is lost. So don't move output
directly to another filesystem. If you need to do this, rename within a single filesystem, wait for new output
to appear and only then move the renamed file to the other filesystem.
Another approach is with symlinks. Make output
a symlink to some name:
ln -s soundfile2.wav output
Then run the command. The target file may not exist, it will be created. If it exists then data will be appended to it.
When you want to switch to another file, atomically update the symlink:
ln -sf soundfile3.wav output
The new file may be on another filesystem, it doesn't matter. Symlinking also allows you to stop saving data without stopping arecord
. Just redirect our ever-running command to /dev/null
:
ln -sf /dev/null output
This may be useful because most likely if you change the symlink again and start saving to a regular file, you will not trigger the pop.
The approaches without or with symlinks can be used together. When output
is a symlink, simply remove it and the next dd
will create output
as a regular file. When output
is a regular file and you want to replace it with a symlink without losing data, hardlink the file to a new name (e.g. ln output soundfile4.wav
) and then atomically replace output
with a symlink.
Notes:
iflag=fullblock
is not portable. If your dd
does not support it then try bs=8 count=48000
. In any case we don't want a transition to a new file happen mid-sample. Our one sample is 8 bytes (32 bits times 2 channels). I'm not familiar enough with arecord
and pipes in Linux, I can only hope the tool will never split a sample to more than one write and therefore dd bs=8
will read full samples even without iflag=fullblock
. But I'm not sure. If dd
ever reads less (compare this) then it will be able to end writing mid-sample and if you change to a new file then the new file will start with an incomplete sample and not play correctly. So if you can use iflag=fullblock
then use it. Remember dd
is a cranky tool which is hard to use correctly; iflag=fullblock
reduces the crankiness.
- You can change
bs
and/or count
to increase or decrease granularity. E.g. bs=38400 count=1
will run 10 dd
processes per second, so the entire setup will be able to switch to a new file almost instantly. On the other hand 10 processes per second may be unnecessary burden. Whatever fits you. Just keep the bs
a multiple of 8.
- When you terminate the command with Ctrl+C, the current
dd
can exit without writing. With bs=384000 count=1
you can lose up to about 1 second of already captured data. While recording important things, postpone Ctrl+C by a second or two.
arecord --max-file-time
maybe? – Kamil Maciorowski Apr 12 '21 at 14:36