/[pcsx2_0.9.7]/trunk/3rdparty/SoundTouch/WavFile.cpp
ViewVC logotype

Contents of /trunk/3rdparty/SoundTouch/WavFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations) (download)
Mon Sep 6 11:19:43 2010 UTC (9 years, 4 months ago) by william
File size: 19191 byte(s)
Exported ./upsream/trunk @r3730 from http://pcsx2.googlecode.com/svn/trunk/
1 ////////////////////////////////////////////////////////////////////////////////
2 ///
3 /// Classes for easy reading & writing of WAV sound files.
4 ///
5 /// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly
6 /// parse the WAV files with such processors.
7 ///
8 /// Admittingly, more complete WAV reader routines may exist in public domain,
9 /// but the reason for 'yet another' one is that those generic WAV reader
10 /// libraries are exhaustingly large and cumbersome! Wanted to have something
11 /// simpler here, i.e. something that's not already larger than rest of the
12 /// SoundTouch/SoundStretch program...
13 ///
14 /// Author : Copyright (c) Olli Parviainen
15 /// Author e-mail : oparviai 'at' iki.fi
16 /// SoundTouch WWW: http://www.surina.net/soundtouch
17 ///
18 ////////////////////////////////////////////////////////////////////////////////
19 //
20 // Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
21 // File revision : $Revision: 4 $
22 //
23 // $Id: WavFile.cpp 63 2009-02-21 16:00:14Z oparviai $
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26 //
27 // License :
28 //
29 // SoundTouch audio processing library
30 // Copyright (c) Olli Parviainen
31 //
32 // This library is free software; you can redistribute it and/or
33 // modify it under the terms of the GNU Lesser General Public
34 // License as published by the Free Software Foundation; either
35 // version 2.1 of the License, or (at your option) any later version.
36 //
37 // This library is distributed in the hope that it will be useful,
38 // but WITHOUT ANY WARRANTY; without even the implied warranty of
39 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40 // Lesser General Public License for more details.
41 //
42 // You should have received a copy of the GNU Lesser General Public
43 // License along with this library; if not, write to the Free Software
44 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
45 //
46 ////////////////////////////////////////////////////////////////////////////////
47
48 #include <stdio.h>
49 #include <stdexcept>
50 #include <string>
51 #include <cstring>
52 #include <assert.h>
53 #include <limits.h>
54
55 #include "WavFile.h"
56
57 using namespace std;
58
59 static const char riffStr[] = "RIFF";
60 static const char waveStr[] = "WAVE";
61 static const char fmtStr[] = "fmt ";
62 static const char dataStr[] = "data";
63
64
65 //////////////////////////////////////////////////////////////////////////////
66 //
67 // Helper functions for swapping byte order to correctly read/write WAV files
68 // with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to
69 // turn-on the conversion if it appears necessary.
70 //
71 // For example, Intel x86 is little-endian and doesn't require conversion,
72 // while PowerPC of Mac's and many other RISC cpu's are big-endian.
73
74 #ifdef BYTE_ORDER
75 // In gcc compiler detect the byte order automatically
76 #if BYTE_ORDER == BIG_ENDIAN
77 // big-endian platform.
78 #define _BIG_ENDIAN_
79 #endif
80 #endif
81
82 #ifdef _BIG_ENDIAN_
83 // big-endian CPU, swap bytes in 16 & 32 bit words
84
85 // helper-function to swap byte-order of 32bit integer
86 static inline void _swap32(unsigned int &dwData)
87 {
88 dwData = ((dwData >> 24) & 0x000000FF) |
89 ((dwData >> 8) & 0x0000FF00) |
90 ((dwData << 8) & 0x00FF0000) |
91 ((dwData << 24) & 0xFF000000);
92 }
93
94 // helper-function to swap byte-order of 16bit integer
95 static inline void _swap16(unsigned short &wData)
96 {
97 wData = ((wData >> 8) & 0x00FF) |
98 ((wData << 8) & 0xFF00);
99 }
100
101 // helper-function to swap byte-order of buffer of 16bit integers
102 static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords)
103 {
104 unsigned long i;
105
106 for (i = 0; i < dwNumWords; i ++)
107 {
108 _swap16(pData[i]);
109 }
110 }
111
112 #else // BIG_ENDIAN
113 // little-endian CPU, WAV file is ok as such
114
115 // dummy helper-function
116 static inline void _swap32(unsigned int &dwData)
117 {
118 // do nothing
119 }
120
121 // dummy helper-function
122 static inline void _swap16(unsigned short &wData)
123 {
124 // do nothing
125 }
126
127 // dummy helper-function
128 static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes)
129 {
130 // do nothing
131 }
132
133 #endif // BIG_ENDIAN
134
135
136 //////////////////////////////////////////////////////////////////////////////
137 //
138 // Class WavInFile
139 //
140
141 WavInFile::WavInFile(const char *fileName)
142 {
143 // Try to open the file for reading
144 fptr = fopen(fileName, "rb");
145 if (fptr == NULL)
146 {
147 // didn't succeed
148 string msg = "Error : Unable to open file \"";
149 msg += fileName;
150 msg += "\" for reading.";
151 throw runtime_error(msg);
152 }
153
154 init();
155 }
156
157
158 WavInFile::WavInFile(FILE *file)
159 {
160 // Try to open the file for reading
161 fptr = file;
162 if (!file)
163 {
164 // didn't succeed
165 string msg = "Error : Unable to access input stream for reading";
166 throw runtime_error(msg);
167 }
168
169 init();
170 }
171
172
173 /// Init the WAV file stream
174 void WavInFile::init()
175 {
176 int hdrsOk;
177
178 // assume file stream is already open
179 assert(fptr);
180
181 // Read the file headers
182 hdrsOk = readWavHeaders();
183 if (hdrsOk != 0)
184 {
185 // Something didn't match in the wav file headers
186 string msg = "Input file is corrupt or not a WAV file";
187 throw runtime_error(msg);
188 }
189
190 if (header.format.fixed != 1)
191 {
192 string msg = "Input file uses unsupported encoding.";
193 throw runtime_error(msg);
194 }
195
196 dataRead = 0;
197 }
198
199
200
201 WavInFile::~WavInFile()
202 {
203 if (fptr) fclose(fptr);
204 fptr = NULL;
205 }
206
207
208
209 void WavInFile::rewind()
210 {
211 int hdrsOk;
212
213 fseek(fptr, 0, SEEK_SET);
214 hdrsOk = readWavHeaders();
215 assert(hdrsOk == 0);
216 dataRead = 0;
217 }
218
219
220 int WavInFile::checkCharTags() const
221 {
222 // header.format.fmt should equal to 'fmt '
223 if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1;
224 // header.data.data_field should equal to 'data'
225 if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1;
226
227 return 0;
228 }
229
230
231 int WavInFile::read(char *buffer, int maxElems)
232 {
233 int numBytes;
234 uint afterDataRead;
235
236 // ensure it's 8 bit format
237 if (header.format.bits_per_sample != 8)
238 {
239 throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples.");
240 }
241 assert(sizeof(char) == 1);
242
243 numBytes = maxElems;
244 afterDataRead = dataRead + numBytes;
245 if (afterDataRead > header.data.data_len)
246 {
247 // Don't read more samples than are marked available in header
248 numBytes = (int)header.data.data_len - (int)dataRead;
249 assert(numBytes >= 0);
250 }
251
252 assert(buffer);
253 numBytes = fread(buffer, 1, numBytes, fptr);
254 dataRead += numBytes;
255
256 return numBytes;
257 }
258
259
260 int WavInFile::read(short *buffer, int maxElems)
261 {
262 unsigned int afterDataRead;
263 int numBytes;
264 int numElems;
265
266 assert(buffer);
267 if (header.format.bits_per_sample == 8)
268 {
269 // 8 bit format
270 char *temp = new char[maxElems];
271 int i;
272
273 numElems = read(temp, maxElems);
274 // convert from 8 to 16 bit
275 for (i = 0; i < numElems; i ++)
276 {
277 buffer[i] = temp[i] << 8;
278 }
279 delete[] temp;
280 }
281 else
282 {
283 // 16 bit format
284 assert(header.format.bits_per_sample == 16);
285 assert(sizeof(short) == 2);
286
287 numBytes = maxElems * 2;
288 afterDataRead = dataRead + numBytes;
289 if (afterDataRead > header.data.data_len)
290 {
291 // Don't read more samples than are marked available in header
292 numBytes = (int)header.data.data_len - (int)dataRead;
293 assert(numBytes >= 0);
294 }
295
296 numBytes = fread(buffer, 1, numBytes, fptr);
297 dataRead += numBytes;
298 numElems = numBytes / 2;
299
300 // 16bit samples, swap byte order if necessary
301 _swap16Buffer((unsigned short *)buffer, numElems);
302 }
303
304 return numElems;
305 }
306
307
308
309 int WavInFile::read(float *buffer, int maxElems)
310 {
311 short *temp = new short[maxElems];
312 int num;
313 int i;
314 double fscale;
315
316 num = read(temp, maxElems);
317
318 fscale = 1.0 / 32768.0;
319 // convert to floats, scale to range [-1..+1[
320 for (i = 0; i < num; i ++)
321 {
322 buffer[i] = (float)(fscale * (double)temp[i]);
323 }
324
325 delete[] temp;
326
327 return num;
328 }
329
330
331 int WavInFile::eof() const
332 {
333 // return true if all data has been read or file eof has reached
334 return (dataRead == header.data.data_len || feof(fptr));
335 }
336
337
338
339 // test if character code is between a white space ' ' and little 'z'
340 static int isAlpha(char c)
341 {
342 return (c >= ' ' && c <= 'z') ? 1 : 0;
343 }
344
345
346 // test if all characters are between a white space ' ' and little 'z'
347 static int isAlphaStr(const char *str)
348 {
349 char c;
350
351 c = str[0];
352 while (c)
353 {
354 if (isAlpha(c) == 0) return 0;
355 str ++;
356 c = str[0];
357 }
358
359 return 1;
360 }
361
362
363 int WavInFile::readRIFFBlock()
364 {
365 if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1;
366
367 // swap 32bit data byte order if necessary
368 _swap32((unsigned int &)header.riff.package_len);
369
370 // header.riff.riff_char should equal to 'RIFF');
371 if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1;
372 // header.riff.wave should equal to 'WAVE'
373 if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1;
374
375 return 0;
376 }
377
378
379
380
381 int WavInFile::readHeaderBlock()
382 {
383 char label[5];
384 string sLabel;
385
386 // lead label string
387 if (fread(label, 1, 4, fptr) !=4) return -1;
388 label[4] = 0;
389
390 if (isAlphaStr(label) == 0) return -1; // not a valid label
391
392 // Decode blocks according to their label
393 if (strcmp(label, fmtStr) == 0)
394 {
395 int nLen, nDump;
396
397 // 'fmt ' block
398 memcpy(header.format.fmt, fmtStr, 4);
399
400 // read length of the format field
401 if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
402 // swap byte order if necessary
403 _swap32((unsigned int &)nLen); // int format_len;
404 header.format.format_len = nLen;
405
406 // calculate how much length differs from expected
407 nDump = nLen - ((int)sizeof(header.format) - 8);
408
409 // if format_len is larger than expected, read only as much data as we've space for
410 if (nDump > 0)
411 {
412 nLen = sizeof(header.format) - 8;
413 }
414
415 // read data
416 if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;
417
418 // swap byte order if necessary
419 _swap16((unsigned short &)header.format.fixed); // short int fixed;
420 _swap16((unsigned short &)header.format.channel_number); // short int channel_number;
421 _swap32((unsigned int &)header.format.sample_rate); // int sample_rate;
422 _swap32((unsigned int &)header.format.byte_rate); // int byte_rate;
423 _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample;
424 _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample;
425
426 // if format_len is larger than expected, skip the extra data
427 if (nDump > 0)
428 {
429 fseek(fptr, nDump, SEEK_CUR);
430 }
431
432 return 0;
433 }
434 else if (strcmp(label, dataStr) == 0)
435 {
436 // 'data' block
437 memcpy(header.data.data_field, dataStr, 4);
438 if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;
439
440 // swap byte order if necessary
441 _swap32((unsigned int &)header.data.data_len);
442
443 return 1;
444 }
445 else
446 {
447 uint len, i;
448 uint temp;
449 // unknown block
450
451 // read length
452 if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;
453 // scan through the block
454 for (i = 0; i < len; i ++)
455 {
456 if (fread(&temp, 1, 1, fptr) != 1) return -1;
457 if (feof(fptr)) return -1; // unexpected eof
458 }
459 }
460 return 0;
461 }
462
463
464 int WavInFile::readWavHeaders()
465 {
466 int res;
467
468 memset(&header, 0, sizeof(header));
469
470 res = readRIFFBlock();
471 if (res) return 1;
472 // read header blocks until data block is found
473 do
474 {
475 // read header blocks
476 res = readHeaderBlock();
477 if (res < 0) return 1; // error in file structure
478 } while (res == 0);
479 // check that all required tags are legal
480 return checkCharTags();
481 }
482
483
484 uint WavInFile::getNumChannels() const
485 {
486 return header.format.channel_number;
487 }
488
489
490 uint WavInFile::getNumBits() const
491 {
492 return header.format.bits_per_sample;
493 }
494
495
496 uint WavInFile::getBytesPerSample() const
497 {
498 return getNumChannels() * getNumBits() / 8;
499 }
500
501
502 uint WavInFile::getSampleRate() const
503 {
504 return header.format.sample_rate;
505 }
506
507
508
509 uint WavInFile::getDataSizeInBytes() const
510 {
511 return header.data.data_len;
512 }
513
514
515 uint WavInFile::getNumSamples() const
516 {
517 if (header.format.byte_per_sample == 0) return 0;
518 return header.data.data_len / (unsigned short)header.format.byte_per_sample;
519 }
520
521
522 uint WavInFile::getLengthMS() const
523 {
524 uint numSamples;
525 uint sampleRate;
526
527 numSamples = getNumSamples();
528 sampleRate = getSampleRate();
529
530 assert(numSamples < UINT_MAX / 1000);
531 return (1000 * numSamples / sampleRate);
532 }
533
534
535 //////////////////////////////////////////////////////////////////////////////
536 //
537 // Class WavOutFile
538 //
539
540 WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
541 {
542 bytesWritten = 0;
543 fptr = fopen(fileName, "wb");
544 if (fptr == NULL)
545 {
546 string msg = "Error : Unable to open file \"";
547 msg += fileName;
548 msg += "\" for writing.";
549 //pmsg = msg.c_str;
550 throw runtime_error(msg);
551 }
552
553 fillInHeader(sampleRate, bits, channels);
554 writeHeader();
555 }
556
557
558 WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)
559 {
560 bytesWritten = 0;
561 fptr = file;
562 if (fptr == NULL)
563 {
564 string msg = "Error : Unable to access output file stream.";
565 throw runtime_error(msg);
566 }
567
568 fillInHeader(sampleRate, bits, channels);
569 writeHeader();
570 }
571
572
573
574 WavOutFile::~WavOutFile()
575 {
576 finishHeader();
577 if (fptr) fclose(fptr);
578 fptr = NULL;
579 }
580
581
582
583 void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
584 {
585 // fill in the 'riff' part..
586
587 // copy string 'RIFF' to riff_char
588 memcpy(&(header.riff.riff_char), riffStr, 4);
589 // package_len unknown so far
590 header.riff.package_len = 0;
591 // copy string 'WAVE' to wave
592 memcpy(&(header.riff.wave), waveStr, 4);
593
594
595 // fill in the 'format' part..
596
597 // copy string 'fmt ' to fmt
598 memcpy(&(header.format.fmt), fmtStr, 4);
599
600 header.format.format_len = 0x10;
601 header.format.fixed = 1;
602 header.format.channel_number = (short)channels;
603 header.format.sample_rate = (int)sampleRate;
604 header.format.bits_per_sample = (short)bits;
605 header.format.byte_per_sample = (short)(bits * channels / 8);
606 header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
607 header.format.sample_rate = (int)sampleRate;
608
609 // fill in the 'data' part..
610
611 // copy string 'data' to data_field
612 memcpy(&(header.data.data_field), dataStr, 4);
613 // data_len unknown so far
614 header.data.data_len = 0;
615 }
616
617
618 void WavOutFile::finishHeader()
619 {
620 // supplement the file length into the header structure
621 header.riff.package_len = bytesWritten + 36;
622 header.data.data_len = bytesWritten;
623
624 writeHeader();
625 }
626
627
628
629 void WavOutFile::writeHeader()
630 {
631 WavHeader hdrTemp;
632 int res;
633
634 // swap byte order if necessary
635 hdrTemp = header;
636 _swap32((unsigned int &)hdrTemp.riff.package_len);
637 _swap32((unsigned int &)hdrTemp.format.format_len);
638 _swap16((unsigned short &)hdrTemp.format.fixed);
639 _swap16((unsigned short &)hdrTemp.format.channel_number);
640 _swap32((unsigned int &)hdrTemp.format.sample_rate);
641 _swap32((unsigned int &)hdrTemp.format.byte_rate);
642 _swap16((unsigned short &)hdrTemp.format.byte_per_sample);
643 _swap16((unsigned short &)hdrTemp.format.bits_per_sample);
644 _swap32((unsigned int &)hdrTemp.data.data_len);
645
646 // write the supplemented header in the beginning of the file
647 fseek(fptr, 0, SEEK_SET);
648 res = fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr);
649 if (res != 1)
650 {
651 throw runtime_error("Error while writing to a wav file.");
652 }
653
654 // jump back to the end of the file
655 fseek(fptr, 0, SEEK_END);
656 }
657
658
659
660 void WavOutFile::write(const char *buffer, int numElems)
661 {
662 int res;
663
664 if (header.format.bits_per_sample != 8)
665 {
666 throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples.");
667 }
668 assert(sizeof(char) == 1);
669
670 res = fwrite(buffer, 1, numElems, fptr);
671 if (res != numElems)
672 {
673 throw runtime_error("Error while writing to a wav file.");
674 }
675
676 bytesWritten += numElems;
677 }
678
679
680 void WavOutFile::write(const short *buffer, int numElems)
681 {
682 int res;
683
684 // 16 bit samples
685 if (numElems < 1) return; // nothing to do
686
687 if (header.format.bits_per_sample == 8)
688 {
689 int i;
690 char *temp = new char[numElems];
691 // convert from 16bit format to 8bit format
692 for (i = 0; i < numElems; i ++)
693 {
694 temp[i] = buffer[i] >> 8;
695 }
696 // write in 8bit format
697 write(temp, numElems);
698 delete[] temp;
699 }
700 else
701 {
702 // 16bit format
703 unsigned short *pTemp = new unsigned short[numElems];
704
705 assert(header.format.bits_per_sample == 16);
706
707 // allocate temp buffer to swap byte order if necessary
708 memcpy(pTemp, buffer, numElems * 2);
709 _swap16Buffer(pTemp, numElems);
710
711 res = fwrite(pTemp, 2, numElems, fptr);
712
713 delete[] pTemp;
714
715 if (res != numElems)
716 {
717 throw runtime_error("Error while writing to a wav file.");
718 }
719 bytesWritten += 2 * numElems;
720 }
721 }
722
723
724 void WavOutFile::write(const float *buffer, int numElems)
725 {
726 int i;
727 short *temp = new short[numElems];
728 int iTemp;
729
730 // convert to 16 bit integer
731 for (i = 0; i < numElems; i ++)
732 {
733 // convert to integer
734 iTemp = (int)(32768.0f * buffer[i]);
735
736 // saturate
737 if (iTemp < -32768) iTemp = -32768;
738 if (iTemp > 32767) iTemp = 32767;
739 temp[i] = (short)iTemp;
740 }
741
742 write(temp, numElems);
743
744 delete[] temp;
745 }

  ViewVC Help
Powered by ViewVC 1.1.22