Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CCSMB 8: Add standard for DFPWM data in WAV files #8

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Standards/CCSMB-8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# *CCSMB 8:* WAV format for DFPWM data
*Author: JackMacWindows <@MCJack123>*

*Version: v1.0.0*

*Last updated: 2023-02-27*

This document describes how to store DFPWM data in a WAV file.

## Overview
DFPWM data is specified through the `WAVE_FORMAT_EXTENDED` data type, with the UUID `3ac1fa38-811d-4361-a40d-ce53ca607cd1`. Channels are stored interleaved, and samples are packed in groups of 8 per byte, as is consistent with raw DFPWM data. Only DFPWM1a data is considered here - original DFPWM should not be stored using this UUID.

## `fmt `&nbsp;chunk
The `fmt `&nbsp;chunk follows the standard layout for `WAVE_FORMAT_EXTENDED`, using the assigned DFPWM UUID:

| Offset | Bytes | Description |
|--------|-------|-------------------------------------------------|
| 0x00 | 2 | Format code (`0xFFFE`) |
| 0x02 | 2 | Number of channels |
| 0x04 | 4 | Sample rate |
| 0x08 | 4 | Byte rate (sample rate * channels / 8) |
| 0x0C | 2 | Block align (ceil(channels / 8)) |
| 0x0E | 2 | Bits per sample (1) |
| 0x10 | 2 | Extra data size (`0x16`) |
| 0x12 | 2 | Valid bits per sample (1) |
| 0x14 | 4 | Channel configuraion |
| 0x18 | 16 | DFPWM UUID (`3ac1fa38811d4361a40dce53ca607cd1`) |

## `fact` chunk
The `fact` chunk is required when using a non-PCM format. This is simply a 32-bit integer specifying the total number of samples in a single channel. This should be equal to `data length * 8 / channels`.

## `data` chunk
The `data` chunk stores the raw DFPWM data. For single channel audio, this is equivalent to existing raw DFPWM files. For multichannel audio, all samples are interleaved in the PCM input to the encoder. This may be implemented by first encoding the native audio representation to interleaved signed (or unsigned, depending on the codec's capabilities) 8-bit PCM, as would be stored in a PCM WAV file, then passed directly to the DFPWM encoder.

All data uses a single encoder instance with `q` and `s` set to 0, and `lt` set to -128. The instance parameters are used throughout the entire data block, and are never reset while encoding or decoding. The samples are decoded sequentially, with the least significant bit first. Since the data is interleaved before encoding, all channels share the same encoder and parameters, switching between channels for each frame. For example, if a byte `0b11001010` is stored in a 2-channel DFPWM file, the first bit (0) is decoded to the left channel, then the second bit (1) is decoded to the right channel, then the third bit (0) is decoded to the left channel, and so on.

## Compliant muxers/demuxers
The following muxers are known to support DFPWM data in WAV files:
- [CC: Tweaked `speaker` program](https://github.com/cc-tweaked/CC-Tweaked/blob/mc-1.19.x/projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/speaker.lua) (since 1.100.9)
- [AUKit](https://github.com/MCJack123/AUKit)
- [FFmpeg libavformat/libavcodec](https://ffmpeg.org) (since FFmpeg 5.1/avcodec 59.22/avformat 59.18)