RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { int size, rate; byte flags; uint16 type; int blockAlign; if (!loadWAVFromStream(*stream, size, rate, flags, &type, &blockAlign)) { if (disposeAfterUse == DisposeAfterUse::YES) delete stream; return 0; } if (type == 17) // MS IMA ADPCM return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMSIma, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); else if (type == 2) // MS ADPCM return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMS, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); // Raw PCM. Just read everything at once. // TODO: More elegant would be to wrap the stream. byte *data = (byte *)malloc(size); assert(data); stream->read(data, size); if (disposeAfterUse == DisposeAfterUse::YES) delete stream; return makeRawStream(data, size, rate, flags); }
RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { int size, rate; byte flags; uint16 type; int blockAlign; if (!loadWAVFromStream(*stream, size, rate, flags, &type, &blockAlign)) { if (disposeAfterUse == DisposeAfterUse::YES) delete stream; return 0; } if (type == 1) { // Raw PCM, make sure the last packet is complete uint sampleSize = (flags & Audio::FLAG_16BITS ? 2 : 1) * (flags & Audio::FLAG_STEREO ? 2 : 1); if (size % sampleSize != 0) { warning("makeWAVStream: Trying to play a WAVE file with an incomplete PCM packet"); size &= ~(sampleSize - 1); } } Common::SeekableReadStream *substream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + size, disposeAfterUse); switch (type) { case 1: // PCM return makePCMStream(substream, rate, flags); case 2: // MS ADPCM return makeADPCMStream(substream, DisposeAfterUse::YES, Audio::kADPCMMS, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); case 17: // MS IMA ADPCM return makeADPCMStream(substream, DisposeAfterUse::YES, Audio::kADPCMMSIma, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); default: // Unknown return 0; } }
AudioStream *makeWAVStream(Common::File &stream) { int size, rate; byte flags; uint16 type; int blockAlign; if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign)) return 0; if (type == 17) // MS IMA ADPCM return makeADPCMStream(&stream, size, kADPCMMSIma, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1); if (type == 2) // MS ADPCM return makeADPCMStream(&stream, size, kADPCMMS, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign); byte *data = (byte *)malloc(size); assert(data); stream.read_noThrow(data, size); // Since we allocated our own buffer for the data, we must set the autofree flag. flags |= Audio::Mixer::FLAG_AUTOFREE; return makeLinearInputStream(rate, flags, data, size, 0, 0); }
RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, bool disposeAfterUse) { if (stream->readUint32BE() != MKTAG('R', 'I', 'F', 'F')) throw Common::Exception("makeWAVStream(): No 'RIFF' header"); /* uint32 fileSize = */ stream->readUint32LE(); if (stream->readUint32BE() != MKTAG('W', 'A', 'V', 'E')) throw Common::Exception("makeWAVStream(): No 'WAVE' RIFF type"); if (stream->readUint32BE() != MKTAG('f', 'm', 't', ' ')) throw Common::Exception("makeWAVStream(): No 'fmt ' chunk"); uint32 fmtLength = stream->readUint32LE(); if (fmtLength < 16) // A valid fmt chunk always contains at least 16 bytes throw Common::Exception("makeWAVStream(): Invalid wave format size %d", fmtLength); // Now parse the WAVEFORMAT(EX) structure uint16 compression = stream->readUint16LE(); uint16 channels = stream->readUint16LE(); uint32 sampleRate = stream->readUint32LE(); /* uint32 avgBytesPerSecond = */ stream->readUint32LE(); uint16 blockAlign = stream->readUint16LE(); uint16 bitsPerSample = stream->readUint16LE(); // Skip over the rest of the fmt chunk. stream->skip(fmtLength - 16); // Skip over all chunks until we hit the data for (;;) { if (stream->readUint32BE() == MKTAG('d', 'a', 't', 'a')) break; if (stream->eos()) throw Common::Exception("makeWAVStream(): Unexpected eos"); stream->skip(stream->readUint32LE()); } uint32 size = stream->readUint32LE(); Common::SeekableSubReadStream *subStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + size, disposeAfterUse); // Return the decoder we need switch (compression) { case kWavePCM: { byte flags = 0; // 8 bit data is unsigned, 16 bit data signed if (bitsPerSample == 8) flags |= FLAG_UNSIGNED; else if (bitsPerSample == 16) flags |= (FLAG_16BITS | FLAG_LITTLE_ENDIAN); else throw Common::Exception("makeWAVStream(): Unsupported PCM bits per sample %d", bitsPerSample); return makePCMStream(subStream, sampleRate, flags, channels, true); } case kWaveMSIMAADPCM: case kWaveMSIMAADPCM2: return makeADPCMStream(subStream, true, size, kADPCMMSIma, sampleRate, channels, blockAlign); case kWaveMSADPCM: return makeADPCMStream(subStream, true, size, kADPCMMS, sampleRate, channels, blockAlign); } throw Common::Exception("makeWAVStream(): Unhandled wave type 0x%04x", compression); return 0; }