Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/patthemav/loom-extract
LOOM CD Audio Converter written in Rust
https://github.com/patthemav/loom-extract
lucasarts rust
Last synced: 13 days ago
JSON representation
LOOM CD Audio Converter written in Rust
- Host: GitHub
- URL: https://github.com/patthemav/loom-extract
- Owner: PatTheMav
- License: mit
- Created: 2021-12-01T19:22:49.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2021-12-01T19:24:45.000Z (about 3 years ago)
- Last Synced: 2024-12-03T16:42:00.679Z (21 days ago)
- Topics: lucasarts, rust
- Language: Rust
- Homepage:
- Size: 3.91 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Loom CDDA Converter
===================This is a single-purpose command-line tool: To convert the `CDDA.SOU` file of the FM Towns-based VGA version of Loom (as sold on e.g. Steam or GOG) into a WAV file for further audio processing.
# The Format
LOOM's VGA version uses a single CD audio track that contains all dialog as well as musical cues much like a radio play which the game seeks to upon corresponding events in-game.
The version distributed on Steam and GOG contains a single file called `CDDA.SOU` that contains this single track, but although its name suggests this to be a PCM-based CD audio (e.g. a simple `AIFF` or `WAV` file) it actually uses a bit-shifted 8-bit format:
| Byte(s) | Description |
| ------- | ----------- |
| 1-800 | Unknown data, considered "garbage" |
| 801 | Bit shift value |
| 802-1978 | 1176 bytes of unshifted audio |
| 1979 | Bit shift value |
| 1980-3156 | 1176 bytes of unshifted audio |# The Conversion
To retrieve the 16-bit audio encoded in the file, each block of 1177 bytes needs to be processed in the same way:
1. Read the first byte - it contains the shift values
2. Shift the upper 4 bits down to yield the shift value for the _left_ channel (`byte_value >> 4`)
3. Mask the lower 4 bits to yield the shift value for the _right_ channel (`byte_value & 0x0F`)
4. Read the second byte and treat it as a _signed_ 8-bit value
5. Convert this value into a _signed_ 16-bit value
6. Left-shift this value by the amount of bits from step #2
7. Read the third byte and repeat step #4
8. Repeat step #5
9. Repeat step #6, but this time use the amount of bits from step #3
10. Continue until reaching a multiple of 1177 bytes, at which point repeat from step #1## Explanation
The `CDDA.SOU` file contains 16-bit stereo audio samples, but encoded to 8-bit values with their lower 8-bits removed. As such this compression is _not_ lossless, as amplitude detail of the first 8 bits is lost - with 15 bits of amplitude in either direction, this comes down to a maximum accuracy loss of 0.7% (and that's at peak amplitude - the lower the volume, the more detail is retained).
Given two bytes (`10011100` for the left channel, and `11100001` for the right channel) and the bit shift value `01000100`, this would evaluate as follows:
```
uint8 bit_shift = 68; // 0100 0100
uint8 left_channel_shift = bit_shift >> 4; // 0100 => 4
uint8 right_channel_shift = bit_shift & 0x0F; // 0100 => 4int8 left_channel_enc = -28 // 1001 1100 => -1 * 001 1100 => -28
int8 right_channel_enc = -113 // 1110 0001 => -1 * 111 0001 => -113int16 left_channel_dec = -448 // 1000 0001 1100 0000 => -1 * 000 0001 1100 0000 => -448
int16 right_channel_dec = -1808 // 1000 0111 0001 0000 => -1 * 000 0111 0001 0000 => -1808
```These decoded 16-bit values can now be written to a file with a proper header for 16-bit little-endian PCM audio and be played as-is.
# A Different Kind Of Hello World
This is the first bit of Rust I've ever written, so code style inadequacies are to be expected 🥴..
# Acknowledgements
* Format discovered by user "apprentice_fu" on the [official ScummVM forums](https://forums.scummvm.org/viewtopic.php?p=64394#p64394)
* Python 2-based extractor by Github user "symm" named [LAAExtract](https://github.com/symm/LAAExtract)