xoreos  0.0.5
xactwavebank_binary.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based heavily on Luigi Auriemma's unxwb tool
26  * (<http://aluigi.altervista.org/papers.htm#xbox>), which is licensed
27  * under the terms of the GPLv2.
28  *
29  * The original copyright note in unxwb reads as follows:
30  *
31  * Copyright 2005-2016 Luigi Auriemma
32  *
33  * This program is free software; you can redistribute it and/or modify
34  * it under the terms of the GNU General Public License as published by
35  * the Free Software Foundation; either version 2 of the License, or
36  * (at your option) any later version.
37  *
38  * This program is distributed in the hope that it will be useful,
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41  * GNU General Public License for more details.
42  *
43  * You should have received a copy of the GNU General Public License
44  * along with this program; if not, write to the Free Software
45  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46  *
47  * http://www.gnu.org/licenses/gpl-2.0.txt
48  *
49  * people who supplied xwb files to analyze [to Luigi]: john deo, antti
50  */
51 
52 #include <cassert>
53 
54 #include "src/common/util.h"
55 #include "src/common/strutil.h"
56 #include "src/common/error.h"
57 #include "src/common/encoding.h"
59 
61 
62 #include "src/sound/decoders/pcm.h"
64 #include "src/sound/decoders/asf.h"
65 
66 namespace Sound {
67 
68 enum XWBFlags {
69  kXWBFlagsStreaming = 0x00000001,
70  kXWBFlagsEntryNames = 0x00010000,
71  kXWBFlagsCompact = 0x00020000,
72  kXWBFlagsSyncDisabled = 0x00040000,
73  kXWBFlagsSeekTables = 0x00080000
74 };
75 
76 enum WaveFlags {
77  kWaveFlagsReadAhead = 0x00000001,
78  kWaveFlagsLoopCache = 0x00000002,
79  kWaveFlagsRemoveLoopTail = 0x00000004,
80  kWaveFlagsIgnoreLoop = 0x00000008
81 };
82 
84  assert(_xwb);
85 
86  load(*_xwb);
87 }
88 
90  return (_flags & kXWBFlagsStreaming) != 0;
91 }
92 
94  return _waves.size();
95 }
96 
98  if (index >= _waves.size())
99  throw Common::Exception("XACTWaveBank_Binary::getWave(): Index out of range (%s >= %s)",
100  Common::composeString(index).c_str(),
101  Common::composeString(_waves.size()).c_str());
102 
103  const Wave &wave = _waves[index];
104 
105  _xwb->seek(wave.offset);
106  Common::ScopedPtr<Common::SeekableReadStream> dataStream(_xwb->readStream(wave.size));
107 
108  switch (wave.codec) {
109  case kCodecPCM:
110  return makePCMStream(dataStream.release(), wave.samplingRate,
112  wave.channels);
113 
114  case kCodecADPCM:
115  return makeADPCMStream(dataStream.release(), true, dataStream->size(),
116  kADPCMXbox, wave.samplingRate, wave.channels);
117 
118  case kCodecWMA:
119  return makeASFStream(dataStream.release());
120 
121  default:
122  throw Common::Exception("XACTWaveBank_Binary::getWave(): Unknown encoding %u",
123  static_cast<uint>(wave.codec));
124  }
125 }
126 
127 
128 enum Segments {
133 
135 };
136 
137 struct Segment {
138  size_t offset;
139  size_t size;
140 };
141 
143  static const uint32 kXWBID = MKTAG('W', 'B', 'N', 'D');
144 
145  const uint32 id = xwb.readUint32BE();
146  if (id != kXWBID)
147  throw Common::Exception("Not a XWB file (%s)", Common::debugTag(id).c_str());
148 
149  const uint32 version = xwb.readUint32LE();
150  if (version != 3)
151  throw Common::Exception("Unsupported XWB file version %u", version);
152 
153  Segment segments[kSegmentMAX];
154 
155  for (size_t i = 0; i < kSegmentMAX; i++) {
156  segments[i].offset = xwb.readUint32LE();
157  segments[i].size = xwb.readUint32LE();
158  }
159 
160  xwb.seek(segments[kSegmentBankData].offset);
161 
162  _flags = xwb.readUint32LE();
163  if (_flags & kXWBFlagsCompact)
164  throw Common::Exception("XACTWaveBank_Binary::load(): TODO: Compact format");
165 
166  const size_t waveCount = xwb.readUint32LE();
167 
169 
170  const size_t waveMetaSize = xwb.readUint32LE();
171  if (waveMetaSize < 24)
172  throw Common::Exception("XACTWaveBank_Binary::load(): Wave meta data size too small (%s)",
173  Common::composeString(waveMetaSize).c_str());
174 
175  xwb.skip(4); // Size of a wave name
176  xwb.skip(4); // Alignment
177 
178  uint32 indexOffset = segments[kSegmentEntryMetaData].offset;
179 
180  uint32 dataOffset = segments[kSegmentWaveData].offset;
181  if (dataOffset == 0)
182  dataOffset = indexOffset + waveCount * waveMetaSize;
183 
184  _waves.resize(waveCount);
185  for (std::vector<Wave>::iterator w = _waves.begin(); w != _waves.end(); ++w) {
186  xwb.seek(indexOffset);
187 
188  w->flags = xwb.readUint32LE();
189 
190  const uint32 formatCode = xwb.readUint32LE();
191 
192  w->offset = xwb.readUint32LE() + dataOffset;
193  w->size = xwb.readUint32LE();
194 
195  w->loopOffset = xwb.readUint32LE();
196  w->loopLength = xwb.readUint32LE();
197 
198  w->codec = static_cast<Codec>(((formatCode ) & ((1 << 2) - 1)));
199  w->channels = (formatCode >> 2) & ((1 << 3) - 1);
200  w->samplingRate = (formatCode >> 5) & ((1 << 18) - 1);
201  w->blockAlign = (formatCode >> 23) & ((1 << 8) - 1);
202  w->bitRate = ((formatCode >> 31) & ((1 << 1) - 1)) ? 16 : 8;
203 
204  switch (w->codec) {
205  case kCodecPCM:
206  case kCodecADPCM:
207  case kCodecWMA:
208  break;
209 
210  default:
211  throw Common::Exception("XACTWaveBank_Binary::load(): Unknown encoding %u",
212  static_cast<uint>(w->codec));
213  }
214 
215  indexOffset += waveMetaSize;
216  }
217 }
218 
219 } // End of namespace Sound
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:133
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
ASF container with a WMA stream.
A binary XACT WaveBank, found in the Xbox version of Jade Empire as XWB files.
UString composeString(T value)
Convert any POD integer, float/double or bool type into a string.
Definition: strutil.cpp:276
RewindableAudioStream * getWave(size_t index) const
Return the audio stream of a wave.
Don&#39;t loop this sound.
Implementing the reading stream interfaces for plain memory blocks.
uint8 bitRate
Number of bits per sample.
unsigned samples (default: signed)
Definition: pcm.h:69
RewindableAudioStream * makePCMStream(Common::SeekableReadStream *stream, int rate, byte flags, int channels, bool disposeAfterUse)
Creates an audio stream, which plays from the given stream.
Definition: pcm.cpp:140
Common::UString _name
The internal name of this wavebank. */.
Codec codec
The codec the wave is in.
Decoding PCM (Pulse Code Modulation).
uint8 channels
Number of channels.
RewindableAudioStream * makeASFStream(Common::SeekableReadStream *stream, bool disposeAfterUse)
Try to load a ASF from the given seekable stream and create a RewindableAudioStream from that data...
Definition: asf.cpp:481
Utility templates and functions for working with strings and streams.
uint32 samplingRate
Sampling frequency in Hz.
Exception that provides a stack of explanations.
Definition: error.h:36
Common::ScopedPtr< Common::SeekableReadStream > _xwb
Definition: game.h:37
Basic exceptions to throw.
Decoding ADPCM (Adaptive Differential Pulse Code Modulation).
A rewindable audio stream.
Definition: audiostream.h:125
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
Utility templates and functions.
Codec
The codec of a wave within the wavebank.
XACTWaveBank_Binary(Common::SeekableReadStream *xwb)
A wave within the wavebank.
RewindableAudioStream * makeADPCMStream(Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 size, ADPCMTypes type, int rate, int channels, uint32 blockAlign)
Takes an input stream containing ADPCM compressed sound data and creates an RewindableAudioStream fro...
Definition: adpcm.cpp:640
Ignore the data after the looping section.
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
Definition: readstream.h:317
Utility functions for working with differing string encodings.
void load(Common::SeekableReadStream &xwb)
StackException Exception
Definition: error.h:59
uint32 readUint32BE()
Read an unsigned 32-bit word stored in big endian (MSB first) order from the stream and return it...
Definition: readstream.h:166
sound is 16 bits wide (default: 8bit)
Definition: pcm.h:72
Plain, unextended ASCII (7bit clean).
Definition: encoding.h:40
uint32_t uint32
Definition: types.h:204
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
Definition: strutil.cpp:117
Audio file is used by at least one looping sound.
samples are little endian (default: big endian)
Definition: pcm.h:75
UString readStringFixed(SeekableReadStream &stream, Encoding encoding, size_t length)
Read length bytes as a string with the given encoding out of a stream.
Definition: encoding.cpp:297
Containerless Xbox ADPCM stream.
bool isStreaming() const
Is this WaveBank rating for streaming, or in-memory play?
Decoding Microsoft&#39;s Advanced Streaming Format.
Interface for a seekable & readable data stream.
Definition: readstream.h:265
size_t offset
The offset of the wave within the wavebank. */.
Performance hint: read ahead while streaming.
size_t getWaveCount() const
Return the number of wave files.
size_t size
The size of the wave in bytes. */.