xoreos  0.0.5
fmodsamplebank.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 fsbext tool
26  * (<http://aluigi.altervista.org/papers.htm#others-file>), which is licensed
27  * under the terms of the GPLv2.
28  *
29  * The original copyright note in fsbext reads as follows:
30  *
31  * Copyright 2005-2012 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 
50 #include <cassert>
51 
52 #include "src/common/error.h"
53 #include "src/common/util.h"
54 #include "src/common/strutil.h"
55 #include "src/common/encoding.h"
56 
57 #include "src/aurora/resman.h"
58 
60 
61 #include "src/sound/decoders/mp3.h"
63 
64 namespace Sound {
65 
67  assert(_fsb);
68 
69  load(*_fsb);
70 }
71 
73  _fsb.reset(ResMan.getResource(name, Aurora::kFileTypeFSB));
74  if (!_fsb)
75  throw Common::Exception("No such FSB resource \"%s\"", name.c_str());
76 
77  load(*_fsb);
78 }
79 
81  return _samples.size();
82 }
83 
84 const Common::UString &FMODSampleBank::getSampleName(size_t index) const {
85  if (index >= _samples.size())
86  throw Common::Exception("FMODSampleBank::getSampleName(): Index out of range (%s >= %s)",
88  Common::composeString(_samples.size()).c_str());
89 
90  return _samples[index].name;
91 }
92 
93 bool FMODSampleBank::hasSample(const Common::UString &name) const {
94  return _sampleMap.find(name) != _sampleMap.end();
95 }
96 
98  kSampleFlagMP3 = 0x00000200,
99  kSampleFlagIMAADPCM = 0x00400000
100 };
101 
103  _fsb->seek(sample.offset);
104  Common::ScopedPtr<Common::SeekableReadStream> dataStream(_fsb->readStream(sample.size));
105 
106  if (sample.flags & kSampleFlagMP3) {
107  warning("MP3");
108  return makeMP3Stream(dataStream.release(), true);
109  }
110 
111  if (sample.flags & kSampleFlagIMAADPCM) {
112  warning("APCM");
113  return makeADPCMStream(dataStream.release(), true, dataStream->size(),
114  kADPCMMSIma, sample.defFreq, sample.channels, 36 * sample.channels);
115  }
116 
117  throw Common::Exception("FMODSampleBank::getSample(): Unknown format (0x%08X)", sample.flags);
118 }
119 
121  if (index >= _samples.size())
122  throw Common::Exception("FMODSampleBank::getSampleName(): Index out of range (%s >= %s)",
123  Common::composeString(index).c_str(),
124  Common::composeString(_samples.size()).c_str());
125 
126  return getSample(_samples[index]);
127 }
128 
130  std::map<Common::UString, const Sample *>::const_iterator s = _sampleMap.find(name);
131  if (s == _sampleMap.end())
132  throw Common::Exception("FMODSampleBank::getSampleName(): No such sample \"%s\"", name.c_str());
133 
134  return getSample(*s->second);
135 }
136 
139 };
140 
142  static const uint32 kFSBID = MKTAG('F', 'S', 'B', '4');
143 
144  const uint32 id = fsb.readUint32BE();
145  if (id != kFSBID)
146  throw Common::Exception("Not a FSB file (%s)", Common::debugTag(id).c_str());
147 
148  const size_t sampleCount = fsb.readUint32LE();
149 
150  const size_t sampleInfoSize = fsb.readUint32LE();
151  fsb.skip(4); // sampleDataSize
152 
153  fsb.skip(4); // version
154  const uint32 flags = fsb.readUint32LE();
155 
156  fsb.skip(24); // Unknown
157 
158  const size_t offsetInfo = 48;
159  size_t offsetData = offsetInfo + sampleInfoSize;
160 
161  fsb.seek(offsetInfo);
162 
163  _samples.resize(sampleCount);
164  for (std::vector<Sample>::iterator s = _samples.begin(); s != _samples.end(); ++s) {
165  const bool isSimple = (flags & kHeaderFlagSimpleInfo) && (s != _samples.begin());
166 
167  if (isSimple) {
168  *s = _samples[0];
169 
170  s->name.clear();
171 
172  s->length = fsb.readUint32LE();
173  s->size = fsb.readUint32LE();
174 
175  } else {
176  const size_t infoSize = fsb.readUint16LE();
177 
178  if (infoSize < 80)
179  throw Common::Exception("FMODSampleBank::load(): Invalid sample info size %s",
180  Common::composeString(infoSize).c_str());
181 
183 
184  s->length = fsb.readUint32LE();
185  s->size = fsb.readUint32LE();
186 
187  s->loopStart = fsb.readUint32LE();
188  s->loopEnd = fsb.readUint32LE();
189 
190  s->flags = fsb.readUint32LE();
191 
192  s->defFreq = fsb.readSint32LE();
193  s->defVol = fsb.readUint16LE();
194  s->defPan = fsb.readSint16LE();
195  s->defPri = fsb.readUint16LE();
196 
197  s->channels = fsb.readUint16LE();
198 
199  s->minDistance = fsb.readIEEEFloatLE();
200  s->maxDistance = fsb.readIEEEFloatLE();
201 
202  s->varFreq = fsb.readSint32LE();
203  s->varVol = fsb.readUint16LE();
204  s->varPan = fsb.readSint16LE();
205 
206  fsb.skip(infoSize - 80);
207  }
208 
209  s->offset = offsetData;
210  offsetData += s->size;
211 
212  if (!s->name.empty())
213  _sampleMap.insert(std::make_pair(s->name, &*s));
214  }
215 }
216 
217 } // End of namespace Sound
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
#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
uint16 readUint16LE()
Read an unsigned 16-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:122
FMODSampleBank(Common::SeekableReadStream *fsb)
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
A class holding an UTF-8 string.
Definition: ustring.h:48
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
bool hasSample(const Common::UString &name) const
Does a sample with this name exist in the sample bank?
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
UString composeString(T value)
Convert any POD integer, float/double or bool type into a string.
Definition: strutil.cpp:276
size_t offset
Offset to the sample within the FSB.
std::vector< Sample > _samples
void load(Common::SeekableReadStream &fsb)
Utility templates and functions for working with strings and streams.
Exception that provides a stack of explanations.
Definition: error.h:36
FORCEINLINE int32 readSint32LE()
Read a signed 32-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:195
An FMOD SampleBank, found in Dragon Age: Origins as FSB files.
size_t size
Size of the sample in bytes.
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
Audio, FMOD sound bank.
Definition: types.h:310
Utility templates and functions.
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
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.
StackException Exception
Definition: error.h:59
FORCEINLINE int16 readSint16LE()
Read a signed 16-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:188
size_t getSampleCount() const
Return the number of sample files.
void warning(const char *s,...)
Definition: util.cpp:33
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
FORCEINLINE float readIEEEFloatLE()
Read a 32-bit IEEE float stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:230
Plain, unextended ASCII (7bit clean).
Definition: encoding.h:40
Common::ScopedPtr< Common::SeekableReadStream > _fsb
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
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
Decoding MP3 (MPEG-1 Audio Layer 3).
RewindableAudioStream * makeMP3Stream(Common::SeekableReadStream *stream, bool disposeAfterUse)
Create a new SeekableAudioStream from the MP3 data in the given stream.
Definition: mp3.cpp:353
RewindableAudioStream * getSample(size_t index) const
Return the audio stream of a sample, by index.
const Common::UString & getSampleName(size_t index) const
Return the name of a sample.
std::map< Common::UString, const Sample * > _sampleMap
Interface for a seekable & readable data stream.
Definition: readstream.h:265
The global resource manager for Aurora resources.