212 lines
7.1 KiB
Markdown
212 lines
7.1 KiB
Markdown
# tuxrecord
|
|
|
|
Record audio to WAV, FLAC or MP3 files on **Linux** using **ALSA** as the
|
|
recording source.
|
|
|
|
`tuxrecord` is the Linux port of the former macOS-only **macrecord** tool. The
|
|
Swift/AVFoundation code was rewritten in **C99** and now uses the native ALSA
|
|
capture API (`libasound`); it builds with **GCC**. WAV output is written
|
|
directly, while FLAC and MP3 are encoded in real time through the system
|
|
`libFLAC` and `libmp3lame` libraries, so no intermediate WAV file is written.
|
|
macrecord was created by my good friend Armin. You can find his code here:
|
|
[https://codeberg.org/armin/macrecord](https://codeberg.org/armin/macrecord)
|
|
|
|
## Requirements
|
|
|
|
- GCC and GNU make
|
|
- ALSA development headers (`libasound2-dev` on Debian/Ubuntu,
|
|
`alsa-lib-devel` on Fedora, `alsa-lib` on Arch)
|
|
- FLAC and LAME (MP3) development headers, used for the real-time encoders
|
|
(`libflac-dev` and `libmp3lame-dev` on Debian/Ubuntu, `flac-devel` and
|
|
`lame-devel` on Fedora, `flac` and `lame` on Arch). They are only needed to
|
|
build; at run time the shared `libFLAC` / `libmp3lame` libraries are used.
|
|
- `pkg-config` (used to locate ALSA, FLAC and LAME)
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
# Record until q or Ctrl+C
|
|
tuxrecord
|
|
|
|
# Record for N seconds
|
|
tuxrecord -d 30
|
|
|
|
# Specify output directory
|
|
tuxrecord -o /path/to/dir
|
|
|
|
# Use a custom filename prefix
|
|
tuxrecord -p myrec
|
|
|
|
# Use a specific ALSA capture device
|
|
tuxrecord -D hw:1,0
|
|
|
|
# Encode to FLAC (lossless) or MP3 (lossy) in real time
|
|
tuxrecord -f flac
|
|
tuxrecord --format mp3
|
|
|
|
# Record from PipeWire (the PipeWire sound server)
|
|
tuxrecord -D pipewire
|
|
```
|
|
|
|
## Options
|
|
|
|
| Option | Description |
|
|
| -------------- | -------------------------------------------------------- |
|
|
| `-o <dir>` | Output directory (default: current directory) |
|
|
| `-d <secs>` | Stop automatically after `<secs>` seconds |
|
|
| `-p <prefix>` | Filename prefix instead of `tuxrecord` |
|
|
| `-D <device>` | ALSA capture device (default: `default`; `pipewire` on PipeWire systems) |
|
|
| `-f, --format <fmt>` | Output format: `wav`, `flac` or `mp3` (default: `wav`) |
|
|
| `-h, --help` | Show help |
|
|
|
|
Run `arecord -l` to list available ALSA capture devices. On systems with
|
|
PipeWire, list the PipeWire source nodes with `pactl list short sources`
|
|
or `wpctl status` (see "Recording from PipeWire" below).
|
|
|
|
## Controls
|
|
|
|
- **q** - Stop recording and save the file
|
|
- **Ctrl+C** - Stop recording and save the file
|
|
|
|
The file is written as `<prefix>__<timestamp>.<ext>` where `<ext>` is `wav`,
|
|
`flac` or `mp3` depending on `-f/--format` (default prefix `tuxrecord`, default
|
|
format `wav`). The VU meter shows the input level of the left and right
|
|
channels in real time when stderr is a terminal.
|
|
|
|
## Output formats
|
|
|
|
Audio is captured once and handed to the selected encoder as it arrives, so
|
|
FLAC and MP3 are produced **in real time** — no intermediate WAV file is
|
|
written and no second conversion pass runs afterwards. A small reusable buffer
|
|
converts the captured 16-bit samples to the layout the encoder expects.
|
|
|
|
- **wav** (default) — uncompressed 16-bit little-endian PCM in a RIFF/WAVE
|
|
container, written directly by tuxrecord.
|
|
- **flac** — lossless compression via libFLAC (streaming, default
|
|
compression level 5).
|
|
- **mp3** — lossy compression via LAME at a constant 192 kbit/s, quality 2.
|
|
|
|
`wav` and `flac` preserve the captured stream exactly; `mp3` is lossy. The
|
|
classic 4 GiB RIFF limit applies to `wav` only (the program stops cleanly
|
|
before exceeding it); `flac` and `mp3` have no such limit.
|
|
|
|
## Recording system audio
|
|
|
|
The default ALSA capture device (`default`) is usually the microphone. To
|
|
record **system audio** (everything playing on the machine), route playback
|
|
through the ALSA loopback driver `snd-aloop` and capture from the other side
|
|
of the loop.
|
|
|
|
```bash
|
|
# 1. Load the loopback module (once per boot)
|
|
sudo modprobe snd-aloop
|
|
|
|
# 2. Play audio on the "playback" side of the loop
|
|
aplay -D hw:Loopback,0 song.wav
|
|
|
|
# 3. In another terminal, record from the paired "capture" side
|
|
tuxrecord -D hw:Loopback,1
|
|
```
|
|
|
|
Audio written to `hw:Loopback,0` (playback) is heard on `hw:Loopback,1`
|
|
(capture): the two subdevices form a loop and the samples pass straight
|
|
through. Point your players at `hw:Loopback,0` (default sink) and record from
|
|
`hw:Loopback,1` to capture the system mix. Subdevice pairing depends on the
|
|
kernel version; if one direction is silent, try recording from
|
|
`hw:Loopback,0` while playing to `hw:Loopback,1`.
|
|
|
|
## Recording from PipeWire
|
|
|
|
On modern distributions (Fedora 34+, Ubuntu 22.04+, Arch Linux) the **PipeWire**
|
|
sound server takes over audio handling. PipeWire ships an ALSA compatibility
|
|
plugin (`pipewire-alsa`) that exposes the server as a normal ALSA capture
|
|
device named `pipewire`, so `tuxrecord` can record from it with no extra
|
|
setup:
|
|
|
|
```bash
|
|
# Record from PipeWire's default source (usually the microphone)
|
|
tuxrecord -D pipewire
|
|
|
|
# Record a fixed duration
|
|
tuxrecord -D pipewire -d 10
|
|
```
|
|
|
|
### What "pipewire" records
|
|
|
|
The pipewire-alsa plugin routes capture to PipeWire's **default source**:
|
|
|
|
```bash
|
|
# Show the current default source
|
|
pactl get-default-source # or: wpctl status
|
|
|
|
# List all available PipeWire sources
|
|
wpctl status
|
|
pactl list short sources
|
|
```
|
|
|
|
### Recording system audio (what you hear)
|
|
|
|
To capture everything that is currently playing (system audio), point the
|
|
default source at the **monitor** of the default sink. This is the PipeWire
|
|
equivalent of the ALSA loopback approach above but needs no kernel module:
|
|
|
|
```bash
|
|
# 1. Find the monitor of the default sink
|
|
pactl set-default-source "$(pactl get-default-sink).monitor"
|
|
|
|
# 2. Record it with tuxrecord
|
|
tuxrecord -D pipewire
|
|
```
|
|
|
|
The `.monitor` source carries exactly what the sink is playing, so anything
|
|
your players output ends up in the recorded file. Every capture follows the
|
|
same `<prefix>__<timestamp>.<ext>` naming and can be stopped with `q` or
|
|
**Ctrl+C**. The default setting can be restored later with
|
|
`pactl set-default-source <your-input-source>`.
|
|
|
|
### Troubleshooting
|
|
|
|
- **"cannot open ALSA capture device 'pipewire'"** — the `pipewire-alsa`
|
|
plugin is missing. Install it (e.g. `pipewire-alsa` on Debian/Ubuntu/Arch,
|
|
`pipewire-alsa` on Fedora), or the PipeWire server is not running
|
|
(`systemctl --user status pipewire`). In that case fall back to a regular
|
|
ALSA device with `tuxrecord -D hw:0,0`.
|
|
- Recording from a specific device or virtual node instead of the default
|
|
source is possible by setting the default source first (see `pactl` /
|
|
`wpctl` output) or by creating a loopback with `pw-loopback` and recording
|
|
that node.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
make
|
|
# or directly:
|
|
# gcc -std=c99 -O2 -Wall -Wextra tuxrecord.c -o tuxrecord \
|
|
# $(pkg-config --cflags --libs alsa flac lame) -lm
|
|
```
|
|
|
|
Install (installs to `$(PREFIX)/bin`, default `/usr/local/bin`):
|
|
|
|
```bash
|
|
sudo make install
|
|
# or: sudo cp tuxrecord /usr/local/bin/tuxrecord
|
|
```
|
|
|
|
Install to a custom prefix:
|
|
|
|
```bash
|
|
make install PREFIX=~/.local
|
|
```
|
|
|
|
Uninstall:
|
|
|
|
```bash
|
|
sudo make uninstall
|
|
```
|
|
|
|
## License
|
|
|
|
Apache License 2.0 — see the LICENSE file for details.
|
|
|
|
Copyright 2026 Johannes Findeisen
|
|
|