1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "common/debug.h"
27 #include "common/util.h"
28 #include "common/stream.h"
30 #include "sound/audiostream.h"
31 #include "sound/mixer.h"
32 #include "sound/wave.h"
33 #include "sound/adpcm.h"
37 bool loadWAVFromStream(Common::SeekableReadStream
&stream
, int &size
, int &rate
, byte
&flags
, uint16
*wavType
, int *blockAlign_
) {
38 const int32 initialPos
= stream
.pos();
44 if (memcmp(buf
, "RIFF", 4) != 0) {
45 warning("getWavInfo: No 'RIFF' header");
49 int32 wavLength
= stream
.readUint32LE();
52 if (memcmp(buf
, "WAVE", 4) != 0) {
53 warning("getWavInfo: No 'WAVE' header");
58 if (memcmp(buf
, "fmt ", 4) != 0) {
59 warning("getWavInfo: No 'fmt' header");
63 uint32 fmtLength
= stream
.readUint32LE();
65 // A valid fmt chunk always contains at least 16 bytes
66 warning("getWavInfo: 'fmt' header is too short");
70 // Next comes the "type" field of the fmt header. Some typical
72 // 1 -> uncompressed PCM
73 // 17 -> IMA ADPCM compressed WAVE
74 // See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete
75 // list of common WAVE compression formats...
76 uint16 type
= stream
.readUint16LE(); // == 1 for PCM data
77 uint16 numChannels
= stream
.readUint16LE(); // 1 for mono, 2 for stereo
78 uint32 samplesPerSec
= stream
.readUint32LE(); // in Hz
79 uint32 avgBytesPerSec
= stream
.readUint32LE(); // == SampleRate * NumChannels * BitsPerSample/8
81 uint16 blockAlign
= stream
.readUint16LE(); // == NumChannels * BitsPerSample/8
82 uint16 bitsPerSample
= stream
.readUint16LE(); // 8, 16 ...
83 // 8 bit data is unsigned, 16 bit data signed
90 *blockAlign_
= blockAlign
;
92 printf("WAVE information:\n");
93 printf(" total size: %d\n", wavLength
);
94 printf(" fmt size: %d\n", fmtLength
);
95 printf(" type: %d\n", type
);
96 printf(" numChannels: %d\n", numChannels
);
97 printf(" samplesPerSec: %d\n", samplesPerSec
);
98 printf(" avgBytesPerSec: %d\n", avgBytesPerSec
);
99 printf(" blockAlign: %d\n", blockAlign
);
100 printf(" bitsPerSample: %d\n", bitsPerSample
);
103 if (type
!= 1 && type
!= 2 && type
!= 17) {
104 warning("getWavInfo: only PCM, MS ADPCM or IMA ADPCM data is supported (type %d)", type
);
108 if (blockAlign
!= numChannels
* bitsPerSample
/ 8 && type
!= 2) {
109 debug(0, "getWavInfo: blockAlign is invalid");
112 if (avgBytesPerSec
!= samplesPerSec
* blockAlign
&& type
!= 2) {
113 debug(0, "getWavInfo: avgBytesPerSec is invalid");
116 // Prepare the return values.
117 rate
= samplesPerSec
;
120 if (bitsPerSample
== 8) // 8 bit data is unsigned
121 flags
|= Audio::Mixer::FLAG_UNSIGNED
;
122 else if (bitsPerSample
== 16) // 16 bit data is signed little endian
123 flags
|= (Audio::Mixer::FLAG_16BITS
| Audio::Mixer::FLAG_LITTLE_ENDIAN
);
124 else if (bitsPerSample
== 4 && type
== 17) // MS IMA ADPCM compressed. We decompress it
125 flags
|= (Audio::Mixer::FLAG_16BITS
| Audio::Mixer::FLAG_LITTLE_ENDIAN
);
126 else if (bitsPerSample
== 4 && type
== 2) // MS ADPCM compressed. We decompress it
127 flags
|= (Audio::Mixer::FLAG_16BITS
| Audio::Mixer::FLAG_LITTLE_ENDIAN
);
129 warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample
);
133 if (numChannels
== 2)
134 flags
|= Audio::Mixer::FLAG_STEREO
;
135 else if (numChannels
!= 1) {
136 warning("getWavInfo: unsupported number of channels %d", numChannels
);
140 // It's almost certainly a WAV file, but we still need to find its
143 // Skip over the rest of the fmt chunk.
144 int offset
= fmtLength
- 16;
147 stream
.seek(offset
, SEEK_CUR
);
148 if (stream
.pos() >= initialPos
+ wavLength
+ 8) {
149 warning("getWavInfo: Can't find 'data' chunk");
153 offset
= stream
.readUint32LE();
156 printf(" found a '%s' tag of size %d\n", buf
, offset
);
158 } while (memcmp(buf
, "data", 4) != 0);
160 // Stream now points at 'offset' bytes of sample data...
166 AudioStream
*makeWAVStream(Common::SeekableReadStream
*stream
, bool disposeAfterUse
) {
172 if (!loadWAVFromStream(*stream
, size
, rate
, flags
, &type
, &blockAlign
)) {
178 if (type
== 17) { // MS IMA ADPCM
179 Audio::AudioStream
*sndStream
= Audio::makeADPCMStream(stream
, false, size
, Audio::kADPCMMSIma
, rate
, (flags
& Audio::Mixer::FLAG_STEREO
) ? 2 : 1, blockAlign
);
180 data
= (byte
*)malloc(size
* 4);
182 size
= sndStream
->readBuffer((int16
*)data
, size
* 2);
183 size
*= 2; // 16bits.
185 } else if (type
== 2) { // MS ADPCM
186 Audio::AudioStream
*sndStream
= Audio::makeADPCMStream(stream
, false, size
, Audio::kADPCMMS
, rate
, (flags
& Audio::Mixer::FLAG_STEREO
) ? 2 : 1, blockAlign
);
187 data
= (byte
*)malloc(size
* 4);
189 size
= sndStream
->readBuffer((int16
*)data
, size
* 2);
190 size
*= 2; // 16bits.
193 // Plain data. Just read everything at once.
194 // TODO: More elegant would be to wrap the stream.
195 data
= (byte
*)malloc(size
);
197 stream
->read(data
, size
);
203 // Since we allocated our own buffer for the data, we must set the autofree flag.
204 flags
|= Audio::Mixer::FLAG_AUTOFREE
;
206 return makeLinearInputStream(data
, size
, rate
, flags
, 0, 0);
209 } // End of namespace Audio