1 /*
2  * Copyright (c) 2009, The MilkyTracker Team.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice,
9  *   this list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * - Neither the name of the <ORGANIZATION> nor the names of its contributors
14  *   may be used to endorse or promote products derived from this software
15  *   without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  *  SampleLoaderWAV.cpp
32  *  MilkyPlay
33  *
34  *  Created by Peter Barth on 14.09.05.
35  *
36  */
37 
38 #include "SampleLoaderWAV.h"
39 #include "XMFile.h"
40 #include "XModule.h"
41 
42 const char* SampleLoaderWAV::channelNames[] = {"Left","Right"};
43 
SampleLoaderWAV(const SYSCHAR * fileName,XModule & theModule)44 SampleLoaderWAV::SampleLoaderWAV(const SYSCHAR* fileName, XModule& theModule) :
45 	SampleLoaderAbstract(fileName, theModule)
46 {
47 }
48 
identifySample()49 bool SampleLoaderWAV::identifySample()
50 {
51 	return getNumChannels() != 0;
52 }
53 
parseFMTChunk(XMFile & f,TWAVHeader & hdr)54 mp_sint32 SampleLoaderWAV::parseFMTChunk(XMFile& f, TWAVHeader& hdr)
55 {
56 	if (hdr.fmtDataLength < 16)
57 		return MP_LOADER_FAILED;
58 
59 	hdr.encodingTag = f.readWord();
60 
61 	if (hdr.encodingTag != 0x1 &&
62 		hdr.encodingTag != 0x3)
63 		return MP_LOADER_FAILED;
64 
65 	hdr.numChannels = f.readWord();
66 
67 	if (hdr.numChannels < 1 || hdr.numChannels > 2)
68 		return MP_LOADER_FAILED;
69 
70 	hdr.sampleRate = f.readDword();
71 	hdr.bytesPerSecond = f.readDword();
72 	hdr.blockAlign = f.readWord();
73 	hdr.numBits = f.readWord();
74 
75 	if (hdr.numBits != 8 &&
76 		hdr.numBits != 16 &&
77 		hdr.numBits != 24 &&
78 		hdr.numBits != 32)
79 		return MP_LOADER_FAILED;
80 
81 	// skip rest of format structure if greater than 16
82 	for (mp_uint32 i = 0; i < hdr.fmtDataLength - 16; i++)
83 		f.readByte();
84 
85 	return MP_OK;
86 }
87 
parseDATAChunk(XMFile & f,TWAVHeader & hdr,mp_sint32 index,mp_sint32 channelIndex)88 mp_sint32 SampleLoaderWAV::parseDATAChunk(XMFile& f, TWAVHeader& hdr, mp_sint32 index, mp_sint32 channelIndex)
89 {
90 	TXMSample* smp = &theModule.smp[index];
91 
92 	if (hdr.dataLength)
93 	{
94 
95 		if (hdr.numBits == 8)
96 		{
97 			if (smp->sample)
98 			{
99 				theModule.freeSampleMem((mp_ubyte*)smp->sample);
100 				smp->sample = NULL;
101 			}
102 			smp->samplen = hdr.dataLength;
103 			if (hdr.numChannels == 2)
104 			{
105 				mp_sbyte* buffer = new mp_sbyte[smp->samplen];
106 				if (buffer == NULL)
107 					return MP_OUT_OF_MEMORY;
108 				theModule.loadSample(f, buffer, smp->samplen, smp->samplen, XModule::ST_UNSIGNED);
109 				smp->samplen>>=1;
110 				smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen);
111 				if (smp->sample == NULL)
112 				{
113 					delete[] buffer;
114 					return MP_OUT_OF_MEMORY;
115 				}
116 				// Downmix channels
117 				if (channelIndex < 0)
118 				{
119 					for (mp_uint32 i = 0; i < smp->samplen; i++)
120 					{
121 						mp_sint32 s1 = buffer[i*2];
122 						mp_sint32 s2 = buffer[i*2+1];
123 						smp->sample[i] = (mp_sbyte)((s1+s2)>>1);
124 					}
125 				}
126 				// take left channel
127 				else if (channelIndex == 0)
128 				{
129 					for (mp_uint32 i = 0; i < smp->samplen; i++)
130 						smp->sample[i] = buffer[i*2];
131 				}
132 				// take right channel
133 				else if (channelIndex == 1)
134 				{
135 					for (mp_uint32 i = 0; i < smp->samplen; i++)
136 						smp->sample[i] = buffer[i*2+1];
137 				}
138 				else
139 					ASSERT(false);
140 				delete[] buffer;
141 			}
142 			else
143 			{
144 				smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen);
145 				if (smp->sample == NULL)
146 					return MP_OUT_OF_MEMORY;
147 				theModule.loadSample(f, smp->sample, smp->samplen, smp->samplen, XModule::ST_UNSIGNED);
148 			}
149 			smp->type = 0;
150 		}
151 		else if (hdr.numBits == 16)
152 		{
153 			if (smp->sample)
154 			{
155 				theModule.freeSampleMem((mp_ubyte*)smp->sample);
156 				smp->sample = NULL;
157 			}
158 			smp->samplen = hdr.dataLength>>1;
159 			if (hdr.numChannels == 2)
160 			{
161 				mp_sword* buffer = new mp_sword[smp->samplen];
162 				if (buffer == NULL)
163 					return MP_OUT_OF_MEMORY;
164 				theModule.loadSample(f, buffer, hdr.dataLength, smp->samplen, XModule::ST_16BIT);
165 				smp->samplen>>=1;
166 				smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
167 				if (smp->sample == NULL)
168 				{
169 					delete[] buffer;
170 					return MP_OUT_OF_MEMORY;
171 				}
172 				mp_sword* sample = (mp_sword*)smp->sample;
173 				// Downmix channels
174 				if (channelIndex < 0)
175 				{
176 					for (mp_uint32 i = 0; i < smp->samplen; i++)
177 					{
178 						mp_sint32 s1 = buffer[i*2];
179 						mp_sint32 s2 = buffer[i*2+1];
180 						sample[i] = (mp_sword)((s1+s2)>>1);
181 					}
182 				}
183 				// take left channel
184 				else if (channelIndex == 0)
185 				{
186 					for (mp_uint32 i = 0; i < smp->samplen; i++)
187 						sample[i] = buffer[i*2];
188 				}
189 				// take right channel
190 				else if (channelIndex == 1)
191 				{
192 					for (mp_uint32 i = 0; i < smp->samplen; i++)
193 						sample[i] = buffer[i*2+1];
194 				}
195 				else
196 					ASSERT(false);
197 				delete[] buffer;
198 			}
199 			else
200 			{
201 				smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
202 				if (smp->sample == NULL)
203 					return MP_OUT_OF_MEMORY;
204 				theModule.loadSample(f, smp->sample, hdr.dataLength, smp->samplen, XModule::ST_16BIT);
205 			}
206 			smp->type = 16;
207 		}
208 		else if (hdr.numBits == 24)
209 		{
210 			if (smp->sample)
211 			{
212 				theModule.freeSampleMem((mp_ubyte*)smp->sample);
213 				smp->sample = NULL;
214 			}
215 			smp->samplen = hdr.dataLength/3;
216 			if (hdr.numChannels == 2)
217 			{
218 				mp_ubyte* buffer = new mp_ubyte[smp->samplen*3];
219 				if (buffer == NULL)
220 					return MP_OUT_OF_MEMORY;
221 				f.read(buffer, 3, smp->samplen);
222 				smp->samplen>>=1;
223 				smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
224 				if (smp->sample == NULL)
225 				{
226 					delete[] buffer;
227 					return MP_OUT_OF_MEMORY;
228 				}
229 				mp_sword* sample = (mp_sword*)smp->sample;
230 				// Downmix channels
231 				if (channelIndex < 0)
232 				{
233 					for (mp_uint32 i = 0; i < smp->samplen; i++)
234 					{
235 						mp_sword s1 = ((mp_sint32)buffer[i*6+1] + (((mp_sint32)buffer[i*6+2])<<8));
236 						mp_sword s2 = ((mp_sint32)buffer[i*6+4] + (((mp_sint32)buffer[i*6+5])<<8));
237 						sample[i] = ((mp_sint32)s1 + (mp_sint32)s2) >> 1;
238 					}
239 				}
240 				// take left channel
241 				else if (channelIndex == 0)
242 				{
243 					for (mp_uint32 i = 0; i < smp->samplen; i++)
244 						sample[i] = ((mp_sint32)buffer[i*6+1] + (((mp_sint32)buffer[i*6+2])<<8));
245 				}
246 				// take right channel
247 				else if (channelIndex == 1)
248 				{
249 					for (mp_uint32 i = 0; i < smp->samplen; i++)
250 						sample[i] = ((mp_sint32)buffer[i*6+4] + (((mp_sint32)buffer[i*6+5])<<8));
251 				}
252 				else
253 					ASSERT(false);
254 				delete[] buffer;
255 			}
256 			else
257 			{
258 				smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
259 				if (smp->sample == NULL)
260 					return MP_OUT_OF_MEMORY;
261 				mp_ubyte* buffer = new mp_ubyte[smp->samplen*3];
262 				if (buffer == NULL)
263 					return MP_OUT_OF_MEMORY;
264 				f.read(buffer, 3, smp->samplen);
265 				mp_sword* sample = (mp_sword*)smp->sample;
266 				for (mp_uint32 i = 0; i < smp->samplen; i++)
267 					sample[i] = ((mp_sint32)buffer[i*3+1] + (((mp_sint32)buffer[i*3+2])<<8));
268 				delete[] buffer;
269 			}
270 			smp->type = 16;
271 		}
272 		else if (hdr.numBits == 32)
273 		{
274 			// 32 bit DWORD sample data?
275 			if (hdr.encodingTag == 0x01)
276 			{
277 				if (smp->sample)
278 				{
279 					theModule.freeSampleMem((mp_ubyte*)smp->sample);
280 					smp->sample = NULL;
281 				}
282 				smp->samplen = hdr.dataLength>>2;
283 
284 				if (hdr.numChannels == 2)
285 				{
286 					mp_sint32* buffer = new mp_sint32[smp->samplen];
287 					if (buffer == NULL)
288 						return MP_OUT_OF_MEMORY;
289 					f.readDwords((mp_dword*)buffer, smp->samplen);
290 					smp->samplen>>=1;
291 					smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
292 					if (smp->sample == NULL)
293 					{
294 						delete[] buffer;
295 						return MP_OUT_OF_MEMORY;
296 					}
297 					mp_sword* sample = (mp_sword*)smp->sample;
298 					// Downmix channels
299 					if (channelIndex < 0)
300 					{
301 						for (mp_uint32 i = 0; i < smp->samplen; i++)
302 						{
303 							mp_sint32 s1 = buffer[i*2]>>16;
304 							mp_sint32 s2 = buffer[i*2+1]>>16;
305 							sample[i] = (mp_sword)((s1+s2)>>1);
306 						}
307 					}
308 					// take left channel
309 					else if (channelIndex == 0)
310 					{
311 						for (mp_uint32 i = 0; i < smp->samplen; i++)
312 							sample[i] = buffer[i*2]>>16;
313 					}
314 					// take right channel
315 					else if (channelIndex == 1)
316 					{
317 						for (mp_uint32 i = 0; i < smp->samplen; i++)
318 							sample[i] = buffer[i*2+1]>>16;
319 					}
320 					else
321 						ASSERT(false);
322 					delete[] buffer;
323 				}
324 				else
325 				{
326 					smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
327 					if (smp->sample == NULL)
328 						return MP_OUT_OF_MEMORY;
329 					mp_sint32* buffer = new mp_sint32[smp->samplen];
330 					if (buffer == NULL)
331 						return MP_OUT_OF_MEMORY;
332 					f.readDwords((mp_dword*)buffer, smp->samplen);
333 					mp_sword* sample = (mp_sword*)smp->sample;
334 					for (mp_uint32 i = 0; i < smp->samplen; i++)
335 						sample[i] = buffer[i]>>16;
336 					delete[] buffer;
337 				}
338 			}
339 			else if (hdr.encodingTag == 0x03)
340 			{
341 				if (smp->sample)
342 				{
343 					theModule.freeSampleMem((mp_ubyte*)smp->sample);
344 					smp->sample = NULL;
345 				}
346 				smp->samplen = hdr.dataLength>>2;
347 
348 				if (hdr.numChannels == 2)
349 				{
350 					float* buffer = new float[smp->samplen];
351 					if (buffer == NULL)
352 						return MP_OUT_OF_MEMORY;
353 					f.readDwords(reinterpret_cast<mp_dword*>(buffer), smp->samplen);
354 					smp->samplen>>=1;
355 					smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
356 					if (smp->sample == NULL)
357 					{
358 						delete[] buffer;
359 						return MP_OUT_OF_MEMORY;
360 					}
361 					mp_sword* sample = (mp_sword*)smp->sample;
362 					// Downmix channels
363 					if (channelIndex < 0)
364 					{
365 						for (mp_uint32 i = 0; i < smp->samplen; i++)
366 						{
367 							mp_sint32 s1 = (mp_sint32)(buffer[i*2]*32767.0f);
368 							mp_sint32 s2 = (mp_sint32)(buffer[i*2+1]*32767.0f);
369 							sample[i] = (mp_sword)((s1+s2)>>1);
370 						}
371 					}
372 					// take left channel
373 					else if (channelIndex == 0)
374 					{
375 						for (mp_uint32 i = 0; i < smp->samplen; i++)
376 							sample[i] = (mp_sint32)(buffer[i*2]*32767.0f);
377 					}
378 					// take right channel
379 					else if (channelIndex == 1)
380 					{
381 						for (mp_uint32 i = 0; i < smp->samplen; i++)
382 							sample[i] = (mp_sint32)(buffer[i*2+1]*32767.0f);
383 					}
384 					else
385 						ASSERT(false);
386 					delete[] buffer;
387 				}
388 				else
389 				{
390 					smp->sample = (mp_sbyte*)theModule.allocSampleMem(smp->samplen*2);
391 					if (smp->sample == NULL)
392 						return MP_OUT_OF_MEMORY;
393 					float* buffer = new float[smp->samplen];
394 					if (buffer == NULL)
395 						return MP_OUT_OF_MEMORY;
396 					f.readDwords(reinterpret_cast<mp_dword*>(buffer), smp->samplen);
397 					mp_sword* sample = (mp_sword*)smp->sample;
398 					for (mp_uint32 i = 0; i < smp->samplen; i++)
399 						sample[i] = (mp_sint32)(buffer[i]*32767.0f);
400 					delete[] buffer;
401 				}
402 			}
403 			smp->type = 16;
404 		}
405 		smp->loopstart = 0;
406 		smp->looplen = 0;
407 
408 		nameToSample(preferredDefaultName, smp);
409 
410 		XModule::convertc4spd(hdr.sampleRate, &smp->finetune, &smp->relnote);
411 		smp->vol = 255;
412 		smp->pan = 0x80;
413 		smp->flags = 3;
414 	}
415 
416 	return MP_OK;
417 }
418 
parseSMPLChunk(XMFile & f,TWAVHeader & hdr,TSamplerChunk & samplerChunk,TSampleLoop & sampleLoop)419 mp_sint32 SampleLoaderWAV::parseSMPLChunk(XMFile& f, TWAVHeader& hdr,
420 										  TSamplerChunk& samplerChunk, TSampleLoop& sampleLoop)
421 {
422 	mp_dword pos = (unsigned)f.pos() + (unsigned)hdr.dataLength;
423 
424 	f.readDwords((mp_dword*)&samplerChunk, sizeof(TSamplerChunk) / sizeof(mp_dword));
425 
426 	if (samplerChunk.cSampleLoops)
427 	{
428 		f.readDwords((mp_dword*)&sampleLoop, sizeof(TSampleLoop) / sizeof(mp_dword));
429 	}
430 
431 	f.seek(pos);
432 	return MP_OK;
433 }
434 
getNumChannels()435 mp_sint32 SampleLoaderWAV::getNumChannels()
436 {
437 	XMFile f(theFileName);
438 
439 	TWAVHeader hdr;
440 
441 	f.read(hdr.RIFF, 1, 4);
442 
443 	if (memcmp(hdr.RIFF, "RIFF", 4))
444 		return 0;
445 
446 	hdr.length = f.readDword();
447 	f.read(hdr.WAVE, 1, 4);
448 
449 	if (memcmp(hdr.WAVE, "WAVE", 4))
450 		return 0;
451 
452 	hdr.numChannels = 0;
453 
454 	do
455 	{
456 		f.read(hdr.FMT, 1, 4);
457 		hdr.fmtDataLength = f.readDword();
458 
459 		// found a "fmt " chunk?
460 		if (memcmp(hdr.FMT, "fmt ", 4) == 0)
461 		{
462 			mp_sint32 res = parseFMTChunk(f, hdr);
463 			if (res < 0)
464 				return 0;
465 			break;
466 		}
467 		else
468 		{
469 			mp_dword pos = (unsigned)f.pos() + (unsigned)hdr.fmtDataLength;
470 
471 			if (pos >= f.size())
472 				break;
473 
474 			f.seek(pos);
475 		}
476 
477 	} while (f.pos() < f.size());
478 
479 	return hdr.numChannels;
480 }
481 
getChannelName(mp_sint32 channelIndex)482 const char* SampleLoaderWAV::getChannelName(mp_sint32 channelIndex)
483 {
484 	if (channelIndex < 2)
485 		return channelNames[channelIndex];
486 	else
487 		return SampleLoaderAbstract::getChannelName(channelIndex);
488 }
489 
loadSample(mp_sint32 index,mp_sint32 channelIndex)490 mp_sint32 SampleLoaderWAV::loadSample(mp_sint32 index, mp_sint32 channelIndex)
491 {
492 	XMFile f(theFileName);
493 
494 	TWAVHeader hdr;
495 
496 	f.read(hdr.RIFF, 1, 4);
497 
498 	if (memcmp(hdr.RIFF, "RIFF", 4))
499 		return MP_LOADER_FAILED;
500 
501 	hdr.length = f.readDword();
502 	f.read(hdr.WAVE, 1, 4);
503 
504 	if (memcmp(hdr.WAVE, "WAVE", 4))
505 		return MP_LOADER_FAILED;
506 
507 	// Start looking for "fmt " chunk
508 	hdr.numChannels = 0;
509 
510 	do
511 	{
512 		f.read(hdr.FMT, 1, 4);
513 		hdr.fmtDataLength = f.readDword();
514 
515 		// found a "fmt " chunk?
516 		if (memcmp(hdr.FMT, "fmt ", 4) == 0)
517 		{
518 			mp_sint32 res = parseFMTChunk(f, hdr);
519 			if (res < 0)
520 				return res;
521 			break;
522 		}
523 		else
524 		{
525 			mp_dword pos = (unsigned)f.pos() + (unsigned)hdr.fmtDataLength;
526 
527 			if (pos >= f.size())
528 				break;
529 
530 			f.seek(pos);
531 		}
532 
533 	} while (f.pos() < f.size());
534 
535 	// check if we found a "fmt " chunk, otherwise the number of channels will be 0
536 	if (hdr.numChannels == 0)
537 		return MP_LOADER_FAILED;
538 
539 	// process remaining chunks
540 
541 	TSamplerChunk samplerChunk;
542 	TSampleLoop sampleLoop;
543 	bool hasSamplerChunk = false;
544 	bool hasData = false;
545 
546 	do
547 	{
548 		mp_sint32 res = f.read(hdr.DATA, 1, 4);
549 		if (res < 4)
550 			break;
551 
552 		hdr.dataLength = f.readDword();
553 
554 		if (memcmp(hdr.DATA, "data", 4) == 0)
555 		{
556 			mp_sint32 res = parseDATAChunk(f, hdr, index, channelIndex);
557 			if (res < 0)
558 				return res;
559 			hasData = true;
560 		}
561 		else if (memcmp(hdr.DATA, "smpl", 4) == 0)
562 		{
563 			mp_sint32 res = parseSMPLChunk(f, hdr, samplerChunk, sampleLoop);
564 			if (res == 0)
565 				hasSamplerChunk = true;
566 		}
567 		else
568 		{
569 			mp_sint32 pos = f.pos() + hdr.dataLength;
570 
571 			if (pos >= (signed)f.size())
572 				break;
573 
574 			f.seek(pos);
575 		}
576 
577 		if (hdr.dataLength & 1)
578 			f.seek(1, XMFile::SeekOffsetTypeCurrent);
579 	} while (f.pos() < f.size());
580 
581 	if (!hasData)
582 		return MP_LOADER_FAILED;
583 
584 	if (hasSamplerChunk && samplerChunk.cSampleLoops)
585 	{
586 		TXMSample* smp = &theModule.smp[index];
587 
588 		mp_dword start = sampleLoop.dwStart/* / (hdr.numBits*hdr.numChannels / 8)*/;
589 		mp_dword end = sampleLoop.dwEnd/* / (hdr.numBits*hdr.numChannels / 8)*/;
590 
591 		if (end > smp->samplen)
592 			end = smp->samplen;
593 
594 		if (start < end && end <= smp->samplen)
595 		{
596 			smp->loopstart = start;
597 			smp->looplen = end - start;
598 			switch (sampleLoop.dwType)
599 			{
600 				case 0:
601 					smp->type|=1;
602 					break;
603 				case 1:
604 					smp->type|=2;
605 					break;
606 			}
607 		}
608 	}
609 
610 	return MP_OK;
611 }
612 
saveSample(const SYSCHAR * fileName,mp_sint32 index)613 mp_sint32 SampleLoaderWAV::saveSample(const SYSCHAR* fileName, mp_sint32 index)
614 {
615 	TXMSample* smp = &theModule.smp[index];
616 
617 	XMFile f(fileName, true);
618 
619 	TWAVHeader hdr;
620 	TSamplerChunk samplerChunk;
621 	TSampleLoop sampleLoop;
622 
623 	bool hasLoop = (smp->type & 3) != 0;
624 
625 	// build wav header
626 	memcpy(hdr.RIFF, "RIFF", 4);
627 	hdr.length = 44 + ((smp->type&16) ? smp->samplen*2 : smp->samplen) - 8 +
628 		(hasLoop ? (sizeof(TSamplerChunk) + sizeof(TSampleLoop) + 8) : 0);
629 	memcpy(hdr.WAVE, "WAVE", 4);
630 	memcpy(hdr.FMT, "fmt ", 4);
631 	hdr.fmtDataLength = 16;
632 	hdr.encodingTag = 1;
633 	hdr.numChannels = 1;
634 	hdr.sampleRate = XModule::getc4spd(smp->relnote,smp->finetune);
635 	hdr.numBits = ((smp->type&16) ? 16 : 8);
636 	hdr.blockAlign = (1*hdr.numBits) / 8;
637 	hdr.bytesPerSecond = hdr.sampleRate*hdr.blockAlign;
638 
639 	f.write(hdr.RIFF, 1, 4);
640 
641 	f.writeDword(hdr.length);
642 	f.write(hdr.WAVE, 1, 4);
643 
644 	f.write(hdr.FMT, 1, 4);
645 
646 	f.writeDword(hdr.fmtDataLength);
647 	f.writeWord(hdr.encodingTag);
648 
649 	f.writeWord(hdr.numChannels);
650 
651 	f.writeDword(hdr.sampleRate);
652 	f.writeDword(hdr.bytesPerSecond);
653 	f.writeWord(hdr.blockAlign);
654 	f.writeWord(hdr.numBits);
655 
656 	if (hasLoop)
657 	{
658 		memcpy(hdr.DATA, "smpl", 4);
659 		hdr.dataLength = sizeof(TSamplerChunk) + sizeof(TSampleLoop);
660 
661 		f.write(hdr.DATA, 1, 4);
662 		f.writeDword(hdr.dataLength);
663 
664 		samplerChunk.cSampleLoops = 1;
665 		samplerChunk.dwSamplePeriod = (mp_dword)(1000.0*1000.0*1000.0 / hdr.sampleRate);
666 
667 		sampleLoop.dwType = ((smp->type & 3) == 2 ? 1 : 0);
668 		sampleLoop.dwStart = smp->loopstart;
669 		sampleLoop.dwEnd = smp->loopstart + smp->looplen;
670 
671 		f.writeDwords((mp_dword*)&samplerChunk, sizeof(samplerChunk) / sizeof(mp_dword));
672 		f.writeDwords((mp_dword*)&sampleLoop, sizeof(sampleLoop) / sizeof(mp_dword));
673 	}
674 
675 	memcpy(hdr.DATA, "data", 4);
676 	hdr.dataLength = (smp->samplen*hdr.numBits)/8;
677 
678 	f.write(hdr.DATA, 1, 4);
679 	f.writeDword(hdr.dataLength);
680 
681 	if (smp->type & 16)
682 	{
683 		for (mp_uint32 i = 0; i < smp->samplen; i++)
684 			f.writeWord(smp->getSampleValue(i));
685 	}
686 	else
687 	{
688 		// WAV 8 bit is unsigned
689 		mp_ubyte* dstPtr = new mp_ubyte[smp->samplen];
690 		mp_ubyte* dst = dstPtr;
691 		for (mp_uint32 i = 0; i < smp->samplen; i++)
692 			*dstPtr++ = ((mp_sbyte)smp->getSampleValue(i))^128;
693 		f.write(dst, 1, smp->samplen);
694 		delete[] dst;
695 	}
696 
697 	return MP_OK;
698 }
699