aboutsummaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/decoders/ac3.cpp201
-rw-r--r--audio/decoders/ac3.h51
-rw-r--r--audio/module.mk5
3 files changed, 256 insertions, 1 deletions
diff --git a/audio/decoders/ac3.cpp b/audio/decoders/ac3.cpp
new file mode 100644
index 0000000000..c569179996
--- /dev/null
+++ b/audio/decoders/ac3.cpp
@@ -0,0 +1,201 @@
+/* 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.
+ *
+ */
+
+#include "common/inttypes.h"
+#include "common/ptr.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/ac3.h"
+#include "audio/decoders/raw.h"
+
+extern "C" {
+#include <a52dec/a52.h>
+}
+
+namespace Audio {
+
+class AC3Stream : public PacketizedAudioStream {
+public:
+ AC3Stream();
+ ~AC3Stream();
+
+ bool init(Common::SeekableReadStream &firstPacket);
+ void deinit();
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples) { return _audStream->readBuffer(buffer, numSamples); }
+ bool isStereo() const { return _audStream->isStereo(); }
+ int getRate() const { return _audStream->getRate(); }
+ bool endOfData() const { return _audStream->endOfData(); }
+ bool endOfStream() const { return _audStream->endOfStream(); }
+
+ // PacketizedAudioStream API
+ void queuePacket(Common::SeekableReadStream *data);
+ void finish() { _audStream->finish(); }
+
+private:
+ Common::ScopedPtr<QueuingAudioStream> _audStream;
+ a52_state_t *_a52State;
+ uint32 _frameSize;
+ byte _inBuf[4096];
+ byte *_inBufPtr;
+ int _flags;
+ int _sampleRate;
+};
+
+AC3Stream::AC3Stream() : _a52State(0), _frameSize(0), _inBufPtr(0), _flags(0), _sampleRate(0) {
+}
+
+AC3Stream::~AC3Stream() {
+ deinit();
+}
+
+enum {
+ HEADER_SIZE = 7
+};
+
+bool AC3Stream::init(Common::SeekableReadStream &firstPacket) {
+ deinit();
+
+ // In theory, I should pass mm_accel() to a52_init(), but I don't know
+ // where that's supposed to be defined.
+ _a52State = a52_init(0);
+
+ // Go through the header to find sync
+ byte buf[HEADER_SIZE];
+ _sampleRate = -1;
+
+ for (uint i = 0; i < firstPacket.size() - sizeof(buf); i++) {
+ int flags, bitRate;
+ firstPacket.seek(i);
+ firstPacket.read(buf, sizeof(buf));
+
+ if (a52_syncinfo(buf, &flags, &_sampleRate, &bitRate) > 0)
+ break;
+ }
+
+ // Ensure we have a valid sample rate
+ if (_sampleRate <= 0) {
+ deinit();
+ return false;
+ }
+
+ _audStream.reset(makeQueuingAudioStream(_sampleRate, true));
+ _inBufPtr = _inBuf;
+ _flags = 0;
+ _frameSize = 0;
+ return true;
+}
+
+void AC3Stream::deinit() {
+ if (!_a52State)
+ return;
+
+ _audStream.reset();
+ a52_free(_a52State);
+ _a52State = 0;
+}
+
+void AC3Stream::queuePacket(Common::SeekableReadStream *data) {
+ Common::ScopedPtr<Common::SeekableReadStream> packet(data);
+
+ while (packet->pos() < packet->size()) {
+ uint32 leftSize = packet->size() - packet->pos();
+ uint32 len = _inBufPtr - _inBuf;
+ if (_frameSize == 0) {
+ // No header seen: find one
+ len = HEADER_SIZE - len;
+ if (len > leftSize)
+ len = leftSize;
+ packet->read(_inBufPtr, len);
+ leftSize -= len;
+ _inBufPtr += len;
+ if ((_inBufPtr - _inBuf) == HEADER_SIZE) {
+ int sampleRate, bitRate;
+ len = a52_syncinfo(_inBuf, &_flags, &sampleRate, &bitRate);
+ if (len == 0) {
+ memmove(_inBuf, _inBuf + 1, HEADER_SIZE - 1);
+ _inBufPtr--;
+ } else {
+ _frameSize = len;
+ }
+ }
+ } else if (len < _frameSize) {
+ len = _frameSize - len;
+ if (len > leftSize)
+ len = leftSize;
+
+ assert(len < sizeof(_inBuf) - (_inBufPtr - _inBuf));
+ packet->read(_inBufPtr, len);
+ leftSize -= len;
+ _inBufPtr += len;
+ } else {
+ // TODO: Eventually support more than just stereo max
+ int flags = A52_STEREO | A52_ADJUST_LEVEL;
+ sample_t level = 32767;
+
+ if (a52_frame(_a52State, _inBuf, &flags, &level, 0) != 0)
+ error("Frame fail");
+
+ int16 *outputBuffer = (int16 *)malloc(6 * 256 * 2 * 2);
+ int16 *outputPtr = outputBuffer;
+ int outputLength = 0;
+ for (int i = 0; i < 6; i++) {
+ if (a52_block(_a52State) == 0) {
+ sample_t *samples = a52_samples(_a52State);
+ for (int j = 0; j < 256; j++) {
+ *outputPtr++ = (int16)samples[j];
+ *outputPtr++ = (int16)samples[j + 256];
+ }
+
+ outputLength += 1024;
+ }
+ }
+
+ if (outputLength > 0) {
+ flags = FLAG_STEREO | FLAG_16BITS;
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ flags |= FLAG_LITTLE_ENDIAN;
+#endif
+
+ _audStream->queueBuffer((byte *)outputBuffer, outputLength, DisposeAfterUse::YES, flags);
+ }
+
+ _inBufPtr = _inBuf;
+ _frameSize = 0;
+ }
+ }
+}
+
+PacketizedAudioStream *makeAC3Stream(Common::SeekableReadStream &firstPacket) {
+ Common::ScopedPtr<AC3Stream> stream(new AC3Stream());
+ if (!stream->init(firstPacket))
+ return 0;
+
+ return stream.release();
+}
+
+} // End of namespace Audio
+
diff --git a/audio/decoders/ac3.h b/audio/decoders/ac3.h
new file mode 100644
index 0000000000..a51107a410
--- /dev/null
+++ b/audio/decoders/ac3.h
@@ -0,0 +1,51 @@
+/* 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.
+ *
+ */
+
+#ifndef AUDIO_DECODERS_AC3_H
+#define AUDIO_DECODERS_AC3_H
+
+#include "common/scummsys.h"
+
+#ifdef USE_A52
+
+namespace Common {
+class SeekableReadStream;
+} // End of namespace Common
+
+namespace Audio {
+
+class PacketizedAudioStream;
+
+/**
+ * Create a PacketizedAudioStream that decodes AC-3 sound
+ *
+ * @param firstPacket The stream containing the first packet of data
+ * @return A new PacketizedAudioStream, or NULL on error
+ */
+PacketizedAudioStream *makeAC3Stream(Common::SeekableReadStream &firstPacket);
+
+} // End of namespace Audio
+
+#endif
+
+#endif
+
diff --git a/audio/module.mk b/audio/module.mk
index 49584aba90..0add7cf291 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -65,7 +65,10 @@ MODULE_OBJS += \
softsynth/opl/nuked.o
endif
-
+ifdef USE_A52
+MODULE_OBJS += \
+ decoders/ac3.o
+endif
ifdef USE_ALSA
MODULE_OBJS += \