# linuxwave turns random bytes into a synthwave track

> linuxwave is a small Zig program that reads bytes from /dev/urandom, a file or standard input and turns them into a waveform written as a WAV file. The scale, note frequency, sample rate, channel count and format are all command line flags, so the same entropy produces a chiptune, a calm ambient bed or a boss theme depending on the preset you pick.

**orhun/linuxwave** — Generate music from the entropy of Linux 🐧🎵

- Repository: https://github.com/orhun/linuxwave
- Website: http://orhun.dev/linuxwave/
- Stars: 665 · Forks: 21
- Language: Zig
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/orhun-linuxwave

## Entropy in, waveform out

linuxwave is described in one line: generate music from the entropy of Linux. The mechanism is simple to describe. The program reads random data, maps it onto a musical scale, and writes the result out as a waveform.

The default run reads random data from /dev/urandom to generate a 20-second music composition in the A4 scale and saves it to output.wav. That is the whole program with no arguments, and it produces an actual audio file rather than a MIDI stream, which means anything that plays WAV files can consume it.

The project traces its inspiration to a bash one liner that composed music from /dev/urandom, and to the Hacker News discussion that followed. The difference linuxwave makes is that it is a real program rather than a shell pipeline, and it is written in Zig, so it also serves as a usable Zig package.

For a developer the interesting angle is that the input is not special. Any file can be the source of the randomness, which turns the tool into a general way of mapping arbitrary data onto audio, and the readme points at a community discussion where people have posted the music they generated this way.

## Building requires Zig 0.17 and produces one binary

The build instructions are two steps. You clone the repository and build it:

```sh
git clone https://github.com/orhun/linuxwave && cd linuxwave/
```

```sh
zig build --release=safe
```

The prerequisite is Zig 0.17, pinned to that version in the instructions. The resulting binary sits at zig-out/bin/linuxwave, and the readme notes that you can also run it directly with zig build run, which is convenient while iterating.

The release safe mode is a deliberate choice for a tool that reads system files. It keeps runtime safety checks on in the optimised build, which costs some speed and buys protection against out of bounds access while parsing input.

There is a second way to consume the project. The readme states that if you want to use linuxwave in your Zig project as a package, the API documentation is published alongside the project, so the same waveform generation is available as a library call rather than only as a command. That makes the tool usable inside a larger Zig program that already has a stream of bytes to turn into sound.

## The options decide what the noise sounds like

The command line interface is where the character comes from. The options list starts like this:

```
Options:
  -s, --scale <SCALE>            Sets the musical scale [default: 0,2,3,5,7,8,10,12]
  -n, --note <HZ>                Sets the frequency of the note [default: 440 (A4)]
  -r, --rate <HZ>                Sets the sample rate [default: 24000]
  -c, --channels <NUM>           Sets the number of channels [default: 1]
  -f, --format <FORMAT>          S
```

The scale is given as semitone offsets, with the default being the major scale across an octave and a bit, and the note flag sets the base frequency, 440 Hz being A4. Everything else follows from those two: the sample rate, the number of channels and the sample format.

The examples show how far the same input can be pushed. A blues scale at 220 Hz gives a different colour from the default, and the note frequency acts as a master pitch, so setting it to 261.63 Hz moves the whole piece to C.

The format flag is worth understanding. The preset examples use values such as S32_LE and U8, so the output is a raw PCM file with a chosen bit depth and endianness rather than a container. That gives control, and it also means a consumer expecting a conventional 16 bit PCM stereo file has to be told which format it is getting.

## Files, stdin and stdout all work as endpoints

The input side is not restricted to random data. Any file can be read, and the readme gives a concrete example that turns the build file of the project itself into ten seconds of music in C major:

```sh
linuxwave -i build.zig -n 261.63 -d 10 -o music.wav
```

Standard input works as well, by passing a dash as the input, so the tool can sit in a pipeline:

```sh
cat README.md | linuxwave -i -
```

And output can be directed to standard output with a dash too:

```sh
linuxwave -o - > output.wav
```

The most useful combination is piping straight into a player, which the readme demonstrates with mpv:

```sh
linuxwave -o - | mpv -
```

That means you can hear the result without writing a file, which is the fastest loop for trying out different scales. It also means the tool composes well with other command line programs, since both ends of the pipeline are ordinary file descriptors.

## Presets show the range from chiptune to ambient

The preset examples in the readme are effectively a set of recipes, and they double as documentation for the flags. A calming track uses a low sample rate and a 32-bit little-endian signed integer format:

```sh
linuxwave -r 2000 -f S32_LE -o calm.wav
```

A chiptune uses the familiar 44100 Hz sample rate, stereo output and an 8-bit unsigned integer format:

```sh
linuxwave -r 44100 -f U8 -c 2 -o chiptune.wav
```

A boss stage theme shrinks the scale to a few notes and lowers the note frequency to 60 Hz while raising the volume:

```sh
linuxwave -s 0,7,1 -n 60 -v 65 -o boss.wav
```

And a spooky low fidelity variant drops the sample rate to 1000 Hz and opens it up to four channels:

```sh
linuxwave -s 0,1,5,3 -n 100 -r 1000 -v 55 -c 4 -o spooky_manor.wav
```

The pattern behind them is clear. Small scale, low note and high volume give a bass heavy, sparse result, while a wide scale at a low sample rate gives a washed out, atmospheric texture. Contributors are invited to submit their own presets as pull requests, and the project also links a discussion thread where the community has posted the tracks they generated.

## Packaging for Arch, Void, Docker and signed release tarballs

linuxwave is distributed in several ways, which says something about how the author expects it to be used.

Arch Linux carries it in the community repository, installed with:

```sh
pacman -S linuxwave
```

Void Linux has it in the official package repository, installed with:

```sh
xbps-install linuxwave
```

Pre-compiled binaries for different targets are on the releases page, and the readme states they are produced by a Continuous Deployment workflow. Release tarballs are signed with a specific PGP key, which is worth noting because it lets a user verify what they downloaded rather than trusting the download channel alone.

Docker images are built automatically and published to two registries, Docker Hub and the GitHub Container Registry. The usage command writes output.wav into the current working directory:

```sh
docker run --rm -v "$(pwd)":/app "orhunp/linuxwave:${TAG:-latest}"
```

The volume mount is what makes that work, since the container writes the file and the host sees it. Custom images can be built from the Dockerfile in the repository with:

```sh
docker build -t linuxwave .
```

## The Docker image compiles in one builder stage and runs as a non root user

The Dockerfile in the repository is short and shows the project's priorities. The builder stage uses the Zig 0.17.0 image, installs git, copies the source and runs the release build:

```dockerfile
FROM eloitor/zig:0.17.0 AS builder
RUN apk update
RUN apk add --no-cache git
WORKDIR /app
COPY . .
RUN zig build --release=safe

FROM alpine:3.8
WORKDIR /app
COPY --from=builder /app/zig-out/bin/linuxwave /usr/local/bin
RUN touch output.wav && \
  chown 1000:1000 output.wav
USER 1000:1000
ENTRYPOINT [ "linuxwave" ]
```

The final stage keeps only the compiled binary on a small Alpine base, and the entrypoint is the program itself, which is why the docker run command in the readme takes no command of its own.

Two details are notable. The image creates an output.wav file and gives it to user 1000 so the non-root user can write to it inside the mounted volume, which is what stops the container from failing with a permission error when it saves the result. And the final base is alpine:3.8, which is a long retired Alpine release, so anyone building images from this Dockerfile for a current environment should update that base themselves.

Outside the container the project also carries the usual packaging artefacts for a command line tool: a man/ directory, a release.sh script, a Dockerfile, build.zig and build.zig.zon, a CHANGELOG.md, a SECURITY.md and a code of conduct.

## Conclusion

Adopt linuxwave when you want a deterministic, dependency free way to turn arbitrary bytes into a playable waveform, for example to generate test audio, placeholder music or ambient sound for a demo, and you are comfortable with a command line tool in Zig. Skip it if you need musically meaningful output, since the mapping from entropy to sound is random by design and no structure, harmony or repetition is produced. Before you use it, build it with zig build --release=safe, check the default scale and note values in the options list, and confirm that the -f format flag matches what your player expects, since the default is not the usual 16 bit PCM a stereo player assumes.

## FAQ

### What does linuxwave do?

It reads random data, by default from /dev/urandom, and turns it into a waveform written as a WAV file. The default run produces a 20-second composition in the A4 scale saved to output.wav.

### How do I build linuxwave from source?

You need Zig 0.17. Clone the repository and run zig build --release=safe. The binary is then at zig-out/bin/linuxwave, and zig build run executes it directly.

### Can linuxwave read from a file or standard input?

Yes. The -i flag selects the input, so you can point it at a file such as build.zig or pass a dash to read from standard input, for example cat README.md | linuxwave -i -. Output can be sent to standard output the same way with -o -.

### Which flags control the sound of linuxwave?

The scale is set with -s, the base note frequency with -n, the sample rate with -r, the channel count with -c and the sample format with -f, plus volume with -v and duration with -d. The defaults are the scale 0,2,3,5,7,8,10,12, note 440 Hz for A4, sample rate 24000 and one channel.

### How is linuxwave packaged and distributed?

It is in the Arch Linux community repository and the official Void Linux repository, pre-compiled binaries are published on the releases page with PGP signed tarballs, and Docker images are built automatically for Docker Hub and the GitHub Container Registry. The licence is MIT and the latest release is v0.4.0.

## Sources

- [License: MIT](https://github.com/orhun/linuxwave/blob/main/LICENSE)
- [orhun/linuxwave on GitHub](https://github.com/orhun/linuxwave)
- [Project website](http://orhun.dev/linuxwave/)
- [README](https://github.com/orhun/linuxwave/blob/main/README.md)
- [Releases](https://github.com/orhun/linuxwave/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/orhun-linuxwave
