aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sword1/music.cpp98
-rw-r--r--sound/aiff.cpp178
-rw-r--r--sound/aiff.h54
-rw-r--r--sound/module.mk1
4 files changed, 331 insertions, 0 deletions
diff --git a/engines/sword1/music.cpp b/engines/sword1/music.cpp
index 209140f9a4..f23b073b58 100644
--- a/engines/sword1/music.cpp
+++ b/engines/sword1/music.cpp
@@ -27,6 +27,7 @@
#include "common/system.h"
#include "sword1/music.h"
+#include "sound/aiff.h"
#include "sound/mixer.h"
#include "sound/mp3.h"
#include "sound/vorbis.h"
@@ -127,6 +128,97 @@ int WaveAudioStream::readBuffer(int16 *buffer, const int numSamples) {
return retVal;
}
+class AiffAudioStream : public Audio::AudioStream {
+public:
+ AiffAudioStream(Common::SeekableReadStream *source, bool loop);
+ virtual ~AiffAudioStream();
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+ virtual bool isStereo() const { return _isStereo; }
+ virtual bool endOfData() const { return (_samplesLeft == 0); }
+ virtual int getRate() const { return _rate; }
+private:
+ Common::SeekableReadStream *_sourceStream;
+ uint8 *_sampleBuf;
+ uint32 _rate;
+ bool _isStereo;
+ uint32 _samplesLeft;
+ uint16 _bitsPerSample;
+ bool _loop;
+
+ void rewind();
+};
+
+AiffAudioStream::AiffAudioStream(Common::SeekableReadStream *source, bool loop) {
+ // TODO: honor the loop flag
+
+ _sourceStream = source;
+ _sampleBuf = (uint8*)malloc(SMP_BUFSIZE);
+
+ _samplesLeft = 0;
+ _isStereo = false;
+ _bitsPerSample = 16;
+ _rate = 22050;
+ _loop = loop;
+
+ rewind();
+
+ if (_samplesLeft == 0)
+ _loop = false;
+}
+
+AiffAudioStream::~AiffAudioStream() {
+ free(_sampleBuf);
+}
+
+void AiffAudioStream::rewind() {
+ int rate, size;
+ byte flags;
+
+ _sourceStream->seek(0);
+
+ if (Audio::loadAIFFFromStream(*_sourceStream, size, rate, flags)) {
+ _isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0;
+ _rate = rate;
+ assert((uint)size <= (_sourceStream->size() - _sourceStream->pos()));
+ _bitsPerSample = ((flags & Audio::Mixer::FLAG_16BITS) != 0) ? 16 : 8;
+ _samplesLeft = (size * 8) / _bitsPerSample;
+ if ((_bitsPerSample != 16) && (_bitsPerSample != 8))
+ error("AiffAudioStream: unknown wave type");
+ }
+}
+
+int AiffAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+ int retVal = 0;
+
+ while (retVal < numSamples && _samplesLeft > 0) {
+ int samples = MIN((int)_samplesLeft, numSamples - retVal);
+ retVal += samples;
+ _samplesLeft -= samples;
+ while (samples > 0) {
+ int readBytes = MIN(samples * (_bitsPerSample >> 3), SMP_BUFSIZE);
+ _sourceStream->read(_sampleBuf, readBytes);
+ if (_bitsPerSample == 16) {
+ readBytes >>= 1;
+ samples -= readBytes;
+ int16 *src = (int16*)_sampleBuf;
+ while (readBytes--)
+ *buffer++ = (int16)READ_BE_UINT16(src++);
+ } else {
+ samples -= readBytes;
+ int8 *src = (int8*)_sampleBuf;
+ while (readBytes--)
+ *buffer++ = (int16)*src++ << 8;
+ }
+ }
+
+ if (!_samplesLeft && _loop) {
+ rewind();
+ }
+ }
+
+ return retVal;
+}
+
// This means fading takes 3 seconds.
#define FADE_LENGTH 3
@@ -156,6 +248,12 @@ bool MusicHandle::play(const char *fileBase, bool loop) {
if (_file.open(fileName))
_audioSource = new WaveAudioStream(&_file, loop);
}
+
+ if (!_audioSource) {
+ sprintf(fileName, "%s.aif", fileBase);
+ if (_file.open(fileName))
+ _audioSource = new AiffAudioStream(&_file, loop);
+ }
if (!_audioSource)
return false;
diff --git a/sound/aiff.cpp b/sound/aiff.cpp
new file mode 100644
index 0000000000..290ebdd9ec
--- /dev/null
+++ b/sound/aiff.cpp
@@ -0,0 +1,178 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2007 The ScummVM project
+ *
+ * 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: wave.cpp 25926 2007-03-02 15:26:22Z fingolfin $
+ *
+ */
+
+/*
+ * 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/stdafx.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/stream.h"
+
+#include "sound/aiff.h"
+#include "sound/audiostream.h"
+#include "sound/mixer.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;
+ 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, bitsPerSample;
+ uint32 numSampleFrames, offset, blockSize, soundOffset;
+
+ while ((!foundCOMM || !foundSSND) && !stream.ioFailed()) {
+ 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::Mixer::FLAG_16BITS;
+ if (numChannels == 2)
+ flags |= Audio::Mixer::FLAG_STEREO;
+
+ stream.seek(soundOffset);
+
+ // Stream now points at the sample data
+
+ return true;
+}
+
+AudioStream *makeAIFFStream(Common::SeekableReadStream &stream) {
+ int size, rate;
+ byte *data, flags;
+
+ if (!loadAIFFFromStream(stream, size, rate, flags))
+ return 0;
+
+ data = (byte *)malloc(size);
+ assert(data);
+ stream.read(data, size);
+
+ // Since we allocated our own buffer for the data, we must set the autofree flag.
+ flags |= Audio::Mixer::FLAG_AUTOFREE;
+
+ return makeLinearInputStream(data, size, rate, flags, 0, 0);
+}
+
+} // End of namespace Audio
diff --git a/sound/aiff.h b/sound/aiff.h
new file mode 100644
index 0000000000..d7e209ac3d
--- /dev/null
+++ b/sound/aiff.h
@@ -0,0 +1,54 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2007 The ScummVM project
+ *
+ * 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: wave.h 22231 2006-04-29 22:33:31Z fingolfin $
+ *
+ */
+
+#ifndef SOUND_AIFF_H
+#define SOUND_AIFF_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+namespace Common { class SeekableReadStream; }
+
+namespace Audio {
+
+class AudioStream;
+
+/**
+ * Try to load an AIFF from the given seekable stream. Returns true if
+ * successful. In that case, the stream's seek position will be set to the
+ * start of the audio data, and size, rate and flags contain information
+ * necessary for playback. Currently this function only supports uncompressed
+ * raw PCM data as well as IMA ADPCM.
+ */
+extern bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags);
+
+/**
+ * Try to load an AIFF from the given seekable stream and create an AudioStream
+ * from that data.
+ *
+ * This function uses loadAIFFFromStream() internally.
+ */
+AudioStream *makeAIFFStream(Common::SeekableReadStream &stream);
+
+} // End of namespace Audio
+
+#endif
diff --git a/sound/module.mk b/sound/module.mk
index ad25b6b31d..dce7ace08e 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -2,6 +2,7 @@ MODULE := sound
MODULE_OBJS := \
adpcm.o \
+ aiff.o \
audiocd.o \
audiostream.o \
flac.o \