Skip to content

Instantly share code, notes, and snippets.

@cs127
Created July 3, 2025 00:08
Show Gist options
  • Save cs127/ad37bcc9dda95e0c2487033487545afe to your computer and use it in GitHub Desktop.
Save cs127/ad37bcc9dda95e0c2487033487545afe to your computer and use it in GitHub Desktop.
NES DMC sample to WAVE converter
// dmdecode v0.00
// extremely simple CLI tool for converting
// Nintendo DMC (1-to-7-bit mono DPCM) samples to 8-bit PCM WAVE
//
// C99 (or newer) required!
//
// cs127
// https://cs127.github.io
// 2025-07-02
#define INITIAL_VALUE 0x40
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#define eprintf(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define fgoto(fp, n) fseek(fp, n, SEEK_SET)
#define fskip(fp, n) fseek(fp, n, SEEK_CUR)
void fputu16(uint16_t v, FILE* fp)
{
fputc(v >> 0 & 0xFF, fp);
fputc(v >> 8 & 0xFF, fp);
}
void fputu32(uint32_t v, FILE* fp)
{
fputc(v >> 0 & 0xFF, fp);
fputc(v >> 8 & 0xFF, fp);
fputc(v >> 16 & 0xFF, fp);
fputc(v >> 24 & 0xFF, fp);
}
int main(int argc, char** argv)
{
register int inv;
register uint8_t outv = INITIAL_VALUE;
register size_t i;
int ret = 0;
long int riff_start, data_start, file_end;
FILE* in = NULL, * out = NULL;
if (argc != 3)
{
eprintf("usage: %s INFILE OUTFILE\n", argv[0]);
ret = 1;
goto end;
}
in = fopen(argv[1], "rb");
if (!in)
{
eprintf("could not open file `%s' for reading.\n", argv[1]);
ret = 3;
goto end;
}
out = fopen(argv[2], "wb");
if (!out)
{
eprintf("could not open file `%s' for writing.\n", argv[2]);
ret = 4;
goto end;
}
// main RIFF file header
fputs("RIFF", out);
fskip(out, 4); // chunk size (written later)
riff_start = ftell(out);
fputs("WAVE", out); // file type
// fmt chunk
fputs("fmt ", out);
fputu32(16, out); // chunk size
fputu16(1, out); // format (1 = integer PCM)
fputu16(1, out); // channel count (1 = mono)
fputu32(33144, out); // sample rate, i.e. sampling points per second
fputu32(33144, out); // bytes per second
fputu16(1, out); // bytes per sampling point
fputu16(8, out); // bit depth
// data chunk
fputs("data", out);
fskip(out, 4); // chunk size (written later)
data_start = ftell(out);
while ((inv = fgetc(in)) != EOF)
{
for (i = 0; i < 8; i++)
{
if (inv & (1 << i))
{
if (outv < 0x7F) outv++;
}
else
{
if (outv > 0x00) outv--;
}
fputc(outv * 2, out);
}
}
file_end = ftell(out);
// go back and write the chunk sizes
fgoto(out, riff_start - 4);
fputu32(file_end - riff_start, out);
fgoto(out, data_start - 4);
fputu32(file_end - data_start, out);
if (ferror(out))
{
eprintf("could not successfully write to `%s'.\n", argv[2]);
ret = 6;
goto end;
}
end:
if (in) fclose(in);
if (out) fclose(out);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment