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

ADPCM WAV support #45

Open
lupine opened this issue May 31, 2020 · 4 comments
Open

ADPCM WAV support #45

lupine opened this issue May 31, 2020 · 4 comments

Comments

@lupine
Copy link

lupine commented May 31, 2020

Hi,

I'm evaluating moving a project of mine to Rust. It's a game engine recreation, and one of the file formats I need to be able to handle is ADPCM-formatted .wav files from 1998 or so 😅. Amethyst uses Hound, and I came across the fact that it's not supported at the moment: https://github.com/ruuda/hound/blob/master/src/read.rs#L537

I suspect nobody's actually creating WAVs of this format any more, but there's a lot of them kicking around from this sort of era. Would you be willing to accept a PR for ADPCM support, in principle? Perhaps implemented as an optional feature?

@ruuda
Copy link
Owner

ruuda commented Jun 2, 2020

Thanks for taking the time to open an issue!

A pull request for ADPCM would be welcome, but before you write any code, it would be good to discuss how this would be implemented. ADPCM looks a lot more complicated in comparison to the currently supported formats (which pretty much store the data in the file as it exists in memory, it is more of a “reading” step than a “decoding” step). I suspect that adding ADPCM will require some significant modifications, because it is more of a compressed format than a container around the raw data.

I should also admit that I have less time to spend on Hound than I would like, so getting a big feature like this reviewed may take me a while. I don’t want to discourage you, but I do want to be honest about this.

If you want to work on this, a very helpful first step would be to collect some resources on how the samples are actually stored in Microsoft ADPCM, i.e. what the meaning of the bits is. After a few minutes of searching, the most useful page I have found so far is this wiki entry. There is also a section on ADPCM in the Microsoft Multimedia Standards Update revision 3.0, on page 24–26, but it is quite terse. Searching for that brought up wavecomp.htm which appears to be the same content. The document references an example conversion program msadpcm.c, but so far I have been unable to find that. A search did bring up an old version of adpcm.c from 1992 in libaudiofile. I think it’s a different program but the same format, it may also be helpful for understanding the bitstream.

@lupine
Copy link
Author

lupine commented Jun 2, 2020

Hey,

Thanks for the reply! Some state-tracking is required, but my understanding is that it's not a great deal. It's a couple of ints per channel in this golang implementation (may not be MS ADPCM, though): https://github.com/JoshuaDoes/adpcm-go/blob/master/status.go

The largest barrier for me is that I barely understand sound or Rust at the moment, but I wasn't expecting it to be a large amount of code 😅.

In terms of design, my first thought was a conversion layer between read and sample that converts the relative (if I can use that word) samples into absolute ones, but I don't know how feasible it is offhand.

On that point, strictly speaking I only need read support - would you require both read and write support before merging, or is the asymmetry acceptable?

I'm not in a huge rush with this - my current approach is to have a preprocessing step that converts the ADPCMs into normal WAVs, so there's no absolute timeline - as long as you're happy with having the support in-principle, I'm happy to do the learning and playing necessary to work it out, then iterate at a leisurely pace until it's up to standard :).

@ruuda
Copy link
Owner

ruuda commented Jun 3, 2020

I barely understand sound or Rust at the moment

If you are learning Rust, keep in mind that Hound is maybe not the most up to date to learn from, it is pretty old for Rust standards. In particular it still uses try!() instead of ?, because I didn’t think it was worth breaking compatibility with older Rust compilers so far. By now ? is probably safe to use.

but I wasn't expecting it to be a large amount of code

Hmm, looking at the Go code you linked, that does indeed look a lot briefer than anything else I could find. Maybe it is not as bad as I thought!

In terms of design, my first thought was a conversion layer between read and sample that converts the relative (if I can use that word) samples into absolute ones, but I don't know how feasible it is offhand.

Just thinking out loud here: It would be nicest if the API could continue to use WavSamples. That struct could track the state for ADPCM too. The downside is that it adds a branch for every sample to check if it needs ADPCM decoding. An alternative would be to expose something to read batches of samples at once. I think that would be nice to have anyway, but it would be a departure from the current API. But maybe we can rebuild WavSamples on top of batched decoding again.

On that point, strictly speaking I only need read support - would you require both read and write support before merging, or is the asymmetry acceptable?

Just read support would already be nice.

I'm happy to do the learning and playing necessary to work it out, then iterate at a leisurely pace until it's up to standard :)

Great!

@lupine
Copy link
Author

lupine commented Oct 25, 2024

I'm coming back to the project that requires this after a long time away, and just wanted to note that in the interim symphonia added codecs for adpcm - two varieties, including adpcm_ms, which is precisely the one I need 😅. pdeljanov/Symphonia#160

Whether it makes sense for hound to pull that in, I don't know. Feel free to close this issue either way!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants