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