1 /**
2  * Read support for the RIFF file format (used in .wav files).
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.utils.sound.riff.reader;
15 
16 import std.algorithm.searching;
17 import std.exception;
18 
19 import ae.utils.sound.riff.common;
20 
21 struct Chunk
22 {
23 	struct Header
24 	{
25 		char[4] name;
26 		uint length;
27 		ubyte[0] data;
28 	}
29 
30 	Header* header;
31 
32 	this(ref ubyte[] data)
33 	{
34 		enforce(data.length >= Header.sizeof);
35 		header = cast(Header*)data;
36 		data = data[Header.sizeof..$];
37 
38 		enforce(data.length >= header.length);
39 		data = data[header.length..$];
40 	}
41 
42 	char[4] name() { return header.name; }
43 	ubyte[] data() { return header.data.ptr[0..header.length]; }
44 }
45 
46 struct Chunks
47 {
48 	ubyte[] data;
49 	bool empty() { return data.length == 0; }
50 	Chunk front() { auto cData = data; return Chunk(cData); }
51 	void popFront() { auto c = Chunk(data); }
52 }
53 
54 auto readRiff(ubyte[] data)
55 {
56 	return Chunk(data);
57 }
58 
59 auto getWave(T)(Chunk chunk)
60 {
61 	enforce(chunk.name == "RIFF", "Unknown file format");
62 	auto riffData = chunk.data;
63 	enforce(riffData.skipOver("WAVE"), "Unknown RIFF contents");
64 	WaveFmt fmt = (cast(WaveFmt[])Chunks(riffData).find!(c => c.name == "fmt ").front.data)[0];
65 	enforce(fmt.format == 1, "Unknown WAVE format");
66 	enforce(fmt.sampleRate * T.sizeof == fmt.byteRate, "Format mismatch");
67 	auto data = Chunks(riffData).find!(c => c.name == "data").front.data;
68 	return cast(T[])data;
69 }