1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Audio.WaveFile;
25 
26 private {
27 	debug import std.stdio;
28 	import std..string : toStringz;
29 	
30 	import derelict.openal.al;
31 	
32 	import Dgame.Internal.Log;
33 	import Dgame.Audio.SoundFile;
34 }
35 
36 struct WaveHeader {
37 	// RIFF - CHUNK
38 	char[4] riff; // Enthält den Namen "RIFF"
39 	uint riff_length;  // Enthält Länge des Riffchunks
40 	char[4] wave;  // Hier steht "WAVE"
41 	// FMT - CHUNK
42 	char[4] fmt;   // Enthält "FMT"
43 	uint fmt_length;    // Länge des fmt-chunks
44 	ushort format;    // 0 = Mono, 1 = Stereo
45 	ushort channels;	// Anz. der benutzten Kanäle
46 	uint sample_rate;	// Sample-Rate in Herz
47 	uint byte_rate;
48 	ushort block_align;
49 	ushort bits_per_sample;
50 	char[4] data;
51 }
52 
53 struct DataHeader {
54 	uint chunkSize;
55 }
56 
57 /**
58  * A Wave implementation of BaseSoundFile
59  * Open a wave file and store the attributes from it's headers.
60  *
61  * Author: rschuett
62  */
63 class WaveFile : BaseSoundFile {
64 protected:
65 	override void _read(string filename) {
66 		FILE* fp = fopen(toStringz(filename), toStringz("rb"));
67 		scope(exit) {
68 			fclose(fp);
69 			fp = null;
70 		}
71 		
72 		WaveHeader wHeader = void;
73 		fread(&wHeader, WaveHeader.sizeof, 1, fp);
74 		
75 		if (wHeader.riff != "RIFF")
76 			throw new Exception("No RIFF: " ~ wHeader.riff.idup);
77 		if (wHeader.wave != "WAVE")
78 			throw new Exception("No WAVE: " ~ wHeader.wave.idup);
79 		if (wHeader.fmt[0 .. 3] != "fmt")
80 			throw new Exception("No fmt: " ~wHeader.fmt.idup);
81 
82 		DataHeader dHeader = void;
83 		if (wHeader.data == "data") {
84 			fread(&dHeader, DataHeader.sizeof, 1, fp);
85 		} else {
86 			throw new Exception("Expected data chunk, not: " ~ wHeader.data.idup);
87 		}
88 
89 		if (dHeader.chunkSize == 0)
90 			throw new Exception("Invalid size");
91 
92 		super._buffer = new byte[dHeader.chunkSize];
93 		fread(super._buffer.ptr, byte.sizeof, dHeader.chunkSize, fp);
94 
95 		super._sFile.rate = wHeader.sample_rate;
96 		super._sFile.dataSize = dHeader.chunkSize;
97 		super._sFile.channels = wHeader.channels;
98 		super._sFile.bits =  wHeader.bits_per_sample;
99 		super._sFile.bytes = wHeader.bits_per_sample / 8;
100 
101 		//writeln(filename, "::", wHeader);
102 
103 		debug Log.info("Allocate %d memory for Wave file %s.", dHeader.chunkSize, filename);
104 	}
105 	
106 public:
107 	/**
108 	 * CTor
109 	 */
110 	this(string filename) {
111 		super(filename);
112 	}
113 	
114 	/**
115 	 * Returns the music type. In this case: wave.
116 	 */
117 	override MusicType getType() const pure nothrow {
118 		return MusicType.Wave;
119 	}
120 }