Skip to content

Instantly share code, notes, and snippets.

@peczenyj
Created May 17, 2026 08:35
Show Gist options
  • Select an option

  • Save peczenyj/4a8991600deb62dfe2b1e93324d1c8bd to your computer and use it in GitHub Desktop.

Select an option

Save peczenyj/4a8991600deb62dfe2b1e93324d1c8bd to your computer and use it in GitHub Desktop.
Wav player
// minimal_wav_player.c
// A minimalistic mono WAV player for Linux using ALSA
// Compile: gcc -o play play.c -lasound
// Usage: ./play file.wav
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <alsa/asoundlib.h>
// WAV header (44 bytes for PCM)
typedef struct {
char riff[4]; // "RIFF"
uint32_t file_size; // total size - 8
char wave[4]; // "WAVE"
char fmt_id[4]; // "fmt "
uint32_t fmt_size; // 16 for PCM
uint16_t format; // 1 = PCM
uint16_t channels; // 1 = mono
uint32_t sample_rate; // e.g. 44100
uint32_t byte_rate; // sample_rate * channels * bits/8
uint16_t block_align; // channels * bits/8
uint16_t bits_per_sample;// 16
char data_id[4]; // "data"
uint32_t data_size; // size of audio data
} WavHeader;
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s file.wav\n", argv[0]);
return 1;
}
// 1. Open WAV file and read header
FILE *fp = fopen(argv[1], "rb");
if (!fp) {
perror("fopen");
return 1;
}
WavHeader hdr;
fread(&hdr, sizeof(hdr), 1, fp);
// Sanity checks
if (memcmp(hdr.riff, "RIFF", 4) != 0 ||
memcmp(hdr.wave, "WAVE", 4) != 0 ||
hdr.format != 1) {
fprintf(stderr, "Not a PCM WAV file\n");
return 1;
}
printf("WAV: %d Hz, %d-bit, %d ch, %d bytes of audio\n",
hdr.sample_rate, hdr.bits_per_sample,
hdr.channels, hdr.data_size);
// 2. Open ALSA device and configure it
snd_pcm_t *pcm;
int err = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (err < 0) {
fprintf(stderr, "snd_pcm_open: %s\n", snd_strerror(err));
return 1;
}
snd_pcm_set_params(pcm,
SND_PCM_FORMAT_S16_LE, // 16-bit signed little-endian
SND_PCM_ACCESS_RW_INTERLEAVED, // interleaved read/write
hdr.channels, // channels from header
hdr.sample_rate, // sample rate from header
1, // allow soft resampling
100000); // latency: 100ms
// 3. Read samples and write to ALSA (the blocking I/O loop)
int frame_size = hdr.channels * (hdr.bits_per_sample / 8);
int buf_frames = 1024;
char *buf = malloc(buf_frames * frame_size);
int frames_read;
while ((frames_read = fread(buf, frame_size, buf_frames, fp)) > 0) {
// This write blocks when the ALSA buffer is full.
// The DAC crystal drains it at sample_rate Hz.
snd_pcm_writei(pcm, buf, frames_read);
}
// 4. Wait for remaining buffered audio to finish playing
snd_pcm_drain(pcm);
// 5. Cleanup
free(buf);
snd_pcm_close(pcm);
fclose(fp);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment