From 42ab839dd6c8a1570b232101eb97f4e54de57935 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 9 Feb 2011 01:09:01 +0000 Subject: AUDIO: Rename sound/ dir to audio/ svn-id: r55850 --- audio/decoders/aiff.cpp | 186 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 audio/decoders/aiff.cpp (limited to 'audio/decoders/aiff.cpp') diff --git a/audio/decoders/aiff.cpp b/audio/decoders/aiff.cpp new file mode 100644 index 0000000000..0f947752f6 --- /dev/null +++ b/audio/decoders/aiff.cpp @@ -0,0 +1,186 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* + * The code in this file is based on information found at + * http://www.borg.com/~jglatt/tech/aiff.htm + * + * We currently only implement uncompressed AIFF. If we ever need AIFF-C, SoX + * (http://sox.sourceforge.net) may be a good place to start from. + */ + +#include "common/endian.h" +#include "common/util.h" +#include "common/stream.h" + +#include "audio/decoders/aiff.h" +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "audio/decoders/raw.h" + +namespace Audio { + +uint32 readExtended(Common::SeekableReadStream &stream) { + // The sample rate is stored as an "80 bit IEEE Standard 754 floating + // point number (Standard Apple Numeric Environment [SANE] data type + // Extended). + + byte buf[10]; + uint32 mantissa; + uint32 last = 0; + byte exp; + + stream.read(buf, 10); + mantissa = READ_BE_UINT32(buf + 2); + exp = 30 - buf[1]; + + while (exp--) { + last = mantissa; + mantissa >>= 1; + } + + if (last & 0x00000001) + mantissa++; + + return mantissa; +} + +bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags) { + byte buf[4]; + + stream.read(buf, 4); + if (memcmp(buf, "FORM", 4) != 0) { + warning("loadAIFFFromStream: No 'FORM' header"); + return false; + } + + stream.readUint32BE(); + + // This could be AIFC, but we don't handle that case. + + stream.read(buf, 4); + if (memcmp(buf, "AIFF", 4) != 0) { + warning("loadAIFFFromStream: No 'AIFF' header"); + return false; + } + + // From here on, we only care about the COMM and SSND chunks, which are + // the only required chunks. + + bool foundCOMM = false; + bool foundSSND = false; + + uint16 numChannels = 0, bitsPerSample = 0; + uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0; + + while (!(foundCOMM && foundSSND) && !stream.err() && !stream.eos()) { + uint32 length, pos; + + stream.read(buf, 4); + length = stream.readUint32BE(); + pos = stream.pos(); + + if (memcmp(buf, "COMM", 4) == 0) { + foundCOMM = true; + numChannels = stream.readUint16BE(); + numSampleFrames = stream.readUint32BE(); + bitsPerSample = stream.readUint16BE(); + rate = readExtended(stream); + size = numSampleFrames * numChannels * (bitsPerSample / 8); + } else if (memcmp(buf, "SSND", 4) == 0) { + foundSSND = true; + offset = stream.readUint32BE(); + blockSize = stream.readUint32BE(); + soundOffset = stream.pos(); + } + + stream.seek(pos + length); + } + + if (!foundCOMM) { + warning("loadAIFFFromStream: Cound not find 'COMM' chunk"); + return false; + } + + if (!foundSSND) { + warning("loadAIFFFromStream: Cound not find 'SSND' chunk"); + return false; + } + + // We only implement a subset of the AIFF standard. + + if (numChannels < 1 || numChannels > 2) { + warning("loadAIFFFromStream: Only 1 or 2 channels are supported, not %d", numChannels); + return false; + } + + if (bitsPerSample != 8 && bitsPerSample != 16) { + warning("loadAIFFFromStream: Only 8 or 16 bits per sample are supported, not %d", bitsPerSample); + return false; + } + + if (offset != 0 || blockSize != 0) { + warning("loadAIFFFromStream: Block-aligned data is not supported"); + return false; + } + + // Samples are always signed, and big endian. + + flags = 0; + if (bitsPerSample == 16) + flags |= Audio::FLAG_16BITS; + if (numChannels == 2) + flags |= Audio::FLAG_STEREO; + + stream.seek(soundOffset); + + // Stream now points at the sample data + + return true; +} + +SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeAfterUse) { + int size, rate; + byte *data, flags; + + if (!loadAIFFFromStream(*stream, size, rate, flags)) { + if (disposeAfterUse == DisposeAfterUse::YES) + delete stream; + return 0; + } + + data = (byte *)malloc(size); + assert(data); + stream->read(data, size); + + if (disposeAfterUse == DisposeAfterUse::YES) + delete stream; + + // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES. + return makeRawStream(data, size, rate, flags); +} + +} // End of namespace Audio -- cgit v1.2.3