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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations) (download)
Mon Sep 6 11:40:06 2010 UTC (9 years, 5 months ago) by william
File size: 19191 byte(s)
exported r3113 from ./upstream/trunk
1 william 10 ////////////////////////////////////////////////////////////////////////////////
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