1 // helper module for xaudio2 tutorial from http://www.win32developer.com/tutorial/xaudio/xaudio_tutorial_1.shtm
2 module wave;
3 
4 import core.stdc..string : memset, memcpy;
5 
6 import std.conv;
7 import std.stdio;
8 
9 import directx.com;
10 import directx.xaudio2;
11 
12 
13 struct Wave
14 {
15 private:
16 	WAVEFORMATEX m_wf;
17 	XAUDIO2_BUFFER m_xa;
18 	ubyte[] m_waveData;
19 public:
20 	this(string szFile) 
21 	{
22 		// i don't like this calls, but let it be here for a moment
23 		memset(&m_wf, 0, m_wf.sizeof);
24 		memset(&m_xa, 0, m_xa.sizeof);
25 
26 		load(szFile);
27 	}
28 	const (XAUDIO2_BUFFER)* xaBuffer() {return &m_xa;}
29 
30 	const (WAVEFORMATEX)* wf() {return &m_wf;}
31 
32 	bool load(string szFile) {
33 
34 		auto file = File(szFile, "rb");	
35 
36 		// additional variables for some hacking
37 		char[4] dwChunkId = 0;
38 		char[4] dwExtra = 0;
39 		byte[4] tmp;
40 		DWORD dwFileSize = 0, dwChunkSize = 0;
41 
42 		file.seek(0);
43 		file.rawRead(dwChunkId);
44 		if( dwChunkId != "RIFF")
45 			return false;
46 
47 		file.seek(4);
48 		file.rawRead(tmp);
49 		dwFileSize = *cast(DWORD*)tmp.ptr;
50 		if(dwFileSize <= 16)
51 			return false;
52 
53 		file.seek(8);
54 		file.rawRead(dwExtra);
55 		if(dwExtra != "WAVE")
56 		{
57 			file.close();
58 			return false;
59 		}
60 
61 		//look for 'fmt ' chunk id
62 		bool bFilledFormat = false;
63 
64 		// byte offset 12 is where the data starts
65 		for(uint i = 12; i < dwFileSize; )
66 		{
67 			file.seek(i);
68 			file.rawRead(dwChunkId);
69 
70 			file.seek(i+4);
71 			file.rawRead(tmp);
72 			dwChunkSize = cast(DWORD)*tmp.ptr;
73 
74 			if(dwChunkId == "fmt ")
75 			{
76 				
77 				byte[WAVEFORMATEX.sizeof] wavetmp;
78 
79 				file.seek(i+8);
80 				file.rawRead(wavetmp);
81 				memcpy(&m_wf, wavetmp.ptr, WAVEFORMATEX.sizeof);
82 				bFilledFormat = true;
83 				break;
84 			}
85 			dwChunkSize += 8; //add offsets of the chunk id, and chunk size data entries
86 			dwChunkSize += 1;
87 			dwChunkSize &= 0xfffffffe; //guarantees WORD padding alignment
88 			i += dwChunkSize;
89 		}
90 		if(!bFilledFormat)
91 		{
92 			file.close();
93 			return false;
94 		}
95 
96 		//look for 'data' chunk id
97 		bool bFilledData = false;
98 		for(uint i = 12; i < dwFileSize; )
99 		{
100 			file.seek(i);
101 			file.rawRead(dwChunkId);
102 
103 			file.seek(i + 4);
104 			file.rawRead(tmp);
105 			dwChunkSize = *cast(DWORD*)tmp.ptr;
106 
107 			if(dwChunkId == "data")
108 			{
109 				m_waveData.length = dwChunkSize;
110 
111 				file.seek(i + 8);
112 				file.rawRead(m_waveData);
113 
114 				m_xa.AudioBytes = dwChunkSize;
115 				m_xa.pAudioData = m_waveData.ptr;
116 				m_xa.PlayBegin = 0;
117 				m_xa.PlayLength = 0;
118 				bFilledData = true;
119 				break;
120 			}
121 			dwChunkSize += 8; //add offsets of the chunk id, and chunk size data entries
122 			dwChunkSize += 1;
123 			dwChunkSize &= 0xfffffffe; //guarantees WORD padding alignment
124 			i += dwChunkSize;
125 		}
126 		if(!bFilledData)
127 		{
128 			file.close();
129 			return false;
130 		}
131 
132 		return true;
133 	}
134 }