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 #include "common/util.h"
00028 
00029 #include "audio/audiostream.h"
00030 #include "audio/decoders/ac3.h"
00031 #include "audio/decoders/raw.h"
00032 
00033 extern "C" {
00034 #include <a52dec/a52.h>
00035 }
00036 
00037 namespace Audio {
00038 
00039 class AC3Stream : public PacketizedAudioStream {
00040 public:
00041     AC3Stream(double decibel);
00042     ~AC3Stream();
00043 
00044     bool init(Common::SeekableReadStream &firstPacket);
00045     void deinit();
00046 
00047     // AudioStream API
00048     int readBuffer(int16 *buffer, const int numSamples) { return _audStream->readBuffer(buffer, numSamples); }
00049     bool isStereo() const { return _audStream->isStereo(); }
00050     int getRate() const { return _audStream->getRate(); }
00051     bool endOfData() const { return _audStream->endOfData(); }
00052     bool endOfStream() const { return _audStream->endOfStream(); }
00053 
00054     // PacketizedAudioStream API
00055     void queuePacket(Common::SeekableReadStream *data);
00056     void finish() { _audStream->finish(); }
00057 
00058 private:
00059     Common::ScopedPtr<QueuingAudioStream> _audStream;
00060     a52_state_t *_a52State;
00061     uint32 _frameSize;
00062     byte _inBuf[4096];
00063     byte *_inBufPtr;
00064     int _flags;
00065     int _sampleRate;
00066     double _audioGain;
00067 };
00068 
00069 AC3Stream::AC3Stream(double decibel) : _a52State(0), _frameSize(0), _inBufPtr(0), _flags(0), _sampleRate(0) {
00070     _audioGain = pow(2, decibel / 6);
00071 }
00072 
00073 AC3Stream::~AC3Stream() {
00074     deinit();
00075 }
00076 
00077 enum {
00078     HEADER_SIZE = 7
00079 };
00080 
00081 bool AC3Stream::init(Common::SeekableReadStream &firstPacket) {
00082     deinit();
00083 
00084     // In theory, I should pass mm_accel() to a52_init(), but I don't know
00085         // where that's supposed to be defined.
00086     _a52State = a52_init(0);
00087 
00088     // Go through the header to find sync
00089     byte buf[HEADER_SIZE];
00090     _sampleRate = -1;
00091 
00092     for (uint i = 0; i < firstPacket.size() - sizeof(buf); i++) {
00093         int flags, bitRate;
00094         firstPacket.seek(i);
00095         firstPacket.read(buf, sizeof(buf));
00096 
00097         if (a52_syncinfo(buf, &flags, &_sampleRate, &bitRate) > 0)
00098             break;
00099     }
00100 
00101     // Ensure we have a valid sample rate
00102     if (_sampleRate <= 0) {
00103         deinit();
00104         return false;
00105     }
00106 
00107     _audStream.reset(makeQueuingAudioStream(_sampleRate, true));
00108     _inBufPtr = _inBuf;
00109     _flags = 0;
00110     _frameSize = 0;
00111     return true;
00112 }
00113 
00114 void AC3Stream::deinit() {
00115     if (!_a52State)
00116         return;
00117 
00118     _audStream.reset();
00119     a52_free(_a52State);
00120     _a52State = 0;
00121 }
00122 
00123 void AC3Stream::queuePacket(Common::SeekableReadStream *data) {
00124     Common::ScopedPtr<Common::SeekableReadStream> packet(data);
00125 
00126     while (packet->pos() < packet->size()) {
00127         uint32 leftSize = packet->size() - packet->pos();
00128         uint32 len = _inBufPtr - _inBuf;
00129         if (_frameSize == 0) {
00130             // No header seen: find one
00131             len = HEADER_SIZE - len;
00132             if (len > leftSize)
00133                 len = leftSize;
00134             packet->read(_inBufPtr, len);
00135             leftSize -= len;
00136             _inBufPtr += len;
00137             if ((_inBufPtr - _inBuf) == HEADER_SIZE) {
00138                 int sampleRate, bitRate;
00139                 len = a52_syncinfo(_inBuf, &_flags, &sampleRate, &bitRate);
00140                 if (len == 0) {
00141                     memmove(_inBuf, _inBuf + 1, HEADER_SIZE - 1);
00142                     _inBufPtr--;
00143                 } else {
00144                     _frameSize = len;
00145                 }
00146             }
00147         } else if (len < _frameSize) {
00148             len = _frameSize - len;
00149             if (len > leftSize)
00150                 len = leftSize;
00151 
00152             assert(len < sizeof(_inBuf) - (_inBufPtr - _inBuf));
00153             packet->read(_inBufPtr, len);
00154             leftSize -= len;
00155             _inBufPtr += len;
00156         } else {
00157             // TODO: Eventually support more than just stereo max
00158             int flags = A52_STEREO | A52_ADJUST_LEVEL;
00159             sample_t level = 32767 * _audioGain;
00160 
00161             if (a52_frame(_a52State, _inBuf, &flags, &level, 0) != 0)
00162                 error("Frame fail");
00163 
00164             int16 *outputBuffer = (int16 *)malloc(6 * 256 * 2 * 2);
00165             int16 *outputPtr = outputBuffer;
00166             int outputLength = 0;
00167             for (int i = 0; i < 6; i++) {
00168                 if (a52_block(_a52State) == 0) {
00169                     sample_t *samples = a52_samples(_a52State);
00170                     for (int j = 0; j < 256; j++) {
00171                         *outputPtr++ = (int16)CLIP<sample_t>(samples[j], -32768, 32767);
00172                         *outputPtr++ = (int16)CLIP<sample_t>(samples[j + 256], -32768, 32767);
00173                     }
00174 
00175                     outputLength += 1024;
00176                 }
00177             }
00178 
00179             if (outputLength > 0) {
00180                 flags = FLAG_STEREO | FLAG_16BITS;
00181 
00182 #ifdef SCUMM_LITTLE_ENDIAN
00183                 flags |= FLAG_LITTLE_ENDIAN;
00184 #endif
00185 
00186                 _audStream->queueBuffer((byte *)outputBuffer, outputLength, DisposeAfterUse::YES, flags);
00187             }
00188 
00189             _inBufPtr = _inBuf;
00190             _frameSize = 0;
00191         }
00192     }
00193 }
00194 
00195 PacketizedAudioStream *makeAC3Stream(Common::SeekableReadStream &firstPacket, double decibel) {
00196     Common::ScopedPtr<AC3Stream> stream(new AC3Stream(decibel));
00197     if (!stream->init(firstPacket))
00198         return 0;
00199 
00200     return stream.release();
00201 }
00202 
00203 } // End of namespace Audio
00204 


Generated on Sat Dec 14 2019 05:00:23 for ResidualVM by doxygen 1.7.1
curved edge   curved edge