ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

ac3.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/inttypes.h"
00024 #include "common/ptr.h"
00025 #include "common/stream.h"
00026 #include "common/textconsole.h"
00027 
00028 #include "audio/audiostream.h"
00029 #include "audio/decoders/ac3.h"
00030 #include "audio/decoders/raw.h"
00031 
00032 extern "C" {
00033 #include <a52dec/a52.h>
00034 }
00035 
00036 namespace Audio {
00037 
00038 class AC3Stream : public PacketizedAudioStream {
00039 public:
00040     AC3Stream();
00041     ~AC3Stream();
00042 
00043     bool init(Common::SeekableReadStream &firstPacket);
00044     void deinit();
00045 
00046     // AudioStream API
00047     int readBuffer(int16 *buffer, const int numSamples) { return _audStream->readBuffer(buffer, numSamples); }
00048     bool isStereo() const { return _audStream->isStereo(); }
00049     int getRate() const { return _audStream->getRate(); }
00050     bool endOfData() const { return _audStream->endOfData(); }
00051     bool endOfStream() const { return _audStream->endOfStream(); }
00052 
00053     // PacketizedAudioStream API
00054     void queuePacket(Common::SeekableReadStream *data);
00055     void finish() { _audStream->finish(); }
00056 
00057 private:
00058     Common::ScopedPtr<QueuingAudioStream> _audStream;
00059     a52_state_t *_a52State;
00060     uint32 _frameSize;
00061     byte _inBuf[4096];
00062     byte *_inBufPtr;
00063     int _flags;
00064     int _sampleRate;
00065 };
00066 
00067 AC3Stream::AC3Stream() : _a52State(0), _frameSize(0), _inBufPtr(0), _flags(0), _sampleRate(0) {
00068 }
00069 
00070 AC3Stream::~AC3Stream() {
00071     deinit();
00072 }
00073 
00074 enum {
00075     HEADER_SIZE = 7
00076 };
00077 
00078 bool AC3Stream::init(Common::SeekableReadStream &firstPacket) {
00079     deinit();
00080 
00081     // In theory, I should pass mm_accel() to a52_init(), but I don't know
00082         // where that's supposed to be defined.
00083     _a52State = a52_init(0);
00084 
00085     // Go through the header to find sync
00086     byte buf[HEADER_SIZE];
00087     _sampleRate = -1;
00088 
00089     for (uint i = 0; i < firstPacket.size() - sizeof(buf); i++) {
00090         int flags, bitRate;
00091         firstPacket.seek(i);
00092         firstPacket.read(buf, sizeof(buf));
00093 
00094         if (a52_syncinfo(buf, &flags, &_sampleRate, &bitRate) > 0)
00095             break;
00096     }
00097 
00098     // Ensure we have a valid sample rate
00099     if (_sampleRate <= 0) {
00100         deinit();
00101         return false;
00102     }
00103 
00104     _audStream.reset(makeQueuingAudioStream(_sampleRate, true));
00105     _inBufPtr = _inBuf;
00106     _flags = 0;
00107     _frameSize = 0;
00108     return true;
00109 }
00110 
00111 void AC3Stream::deinit() {
00112     if (!_a52State)
00113         return;
00114 
00115     _audStream.reset();
00116     a52_free(_a52State);
00117     _a52State = 0;
00118 }
00119 
00120 void AC3Stream::queuePacket(Common::SeekableReadStream *data) {
00121     Common::ScopedPtr<Common::SeekableReadStream> packet(data);
00122 
00123     while (packet->pos() < packet->size()) {
00124         uint32 leftSize = packet->size() - packet->pos();
00125         uint32 len = _inBufPtr - _inBuf;
00126         if (_frameSize == 0) {
00127             // No header seen: find one
00128             len = HEADER_SIZE - len;
00129             if (len > leftSize)
00130                 len = leftSize;
00131             packet->read(_inBufPtr, len);
00132             leftSize -= len;
00133             _inBufPtr += len;
00134             if ((_inBufPtr - _inBuf) == HEADER_SIZE) {
00135                 int sampleRate, bitRate;
00136                 len = a52_syncinfo(_inBuf, &_flags, &sampleRate, &bitRate);
00137                 if (len == 0) {
00138                     memmove(_inBuf, _inBuf + 1, HEADER_SIZE - 1);
00139                     _inBufPtr--;
00140                 } else {
00141                     _frameSize = len;
00142                 }
00143             }
00144         } else if (len < _frameSize) {
00145             len = _frameSize - len;
00146             if (len > leftSize)
00147                 len = leftSize;
00148 
00149             assert(len < sizeof(_inBuf) - (_inBufPtr - _inBuf));
00150             packet->read(_inBufPtr, len);
00151             leftSize -= len;
00152             _inBufPtr += len;
00153         } else {
00154             // TODO: Eventually support more than just stereo max
00155             int flags = A52_STEREO | A52_ADJUST_LEVEL;
00156             sample_t level = 32767;
00157 
00158             if (a52_frame(_a52State, _inBuf, &flags, &level, 0) != 0)
00159                 error("Frame fail");
00160 
00161             int16 *outputBuffer = (int16 *)malloc(6 * 256 * 2 * 2);
00162             int16 *outputPtr = outputBuffer;
00163             int outputLength = 0;
00164             for (int i = 0; i < 6; i++) {
00165                 if (a52_block(_a52State) == 0) {
00166                     sample_t *samples = a52_samples(_a52State);
00167                     for (int j = 0; j < 256; j++) {
00168                         *outputPtr++ = (int16)samples[j];
00169                         *outputPtr++ = (int16)samples[j + 256];
00170                     }
00171 
00172                     outputLength += 1024;
00173                 }
00174             }
00175 
00176             if (outputLength > 0) {
00177                 flags = FLAG_STEREO | FLAG_16BITS;
00178 
00179 #ifdef SCUMM_LITTLE_ENDIAN
00180                 flags |= FLAG_LITTLE_ENDIAN;
00181 #endif
00182 
00183                 _audStream->queueBuffer((byte *)outputBuffer, outputLength, DisposeAfterUse::YES, flags);
00184             }
00185 
00186             _inBufPtr = _inBuf;
00187             _frameSize = 0;
00188         }
00189     }
00190 }
00191 
00192 PacketizedAudioStream *makeAC3Stream(Common::SeekableReadStream &firstPacket) {
00193     Common::ScopedPtr<AC3Stream> stream(new AC3Stream());
00194     if (!stream->init(firstPacket))
00195         return 0;
00196 
00197     return stream.release();
00198 }
00199 
00200 } // End of namespace Audio
00201 


Generated on Sat May 18 2019 05:00:54 for ResidualVM by doxygen 1.7.1
curved edge   curved edge