synced rest files, missed with last sync rev 47951

This commit is contained in:
Pawel Kolodziejski 2011-04-10 15:45:37 +02:00
parent 41be88f8b7
commit bccbcae43c
71 changed files with 977 additions and 3420 deletions

View File

@ -9,7 +9,7 @@ srcdir ?= .
DEFINES := -DHAVE_CONFIG_H
LDFLAGS :=
INCLUDES := -I. -I$(srcdir)
INCLUDES := -I. -I$(srcdir) -I$(srcdir)/engines
LIBS :=
OBJS :=
DEPDIR := .deps
@ -34,7 +34,7 @@ ifeq "$(HAVE_GCC)" "1"
# being helpful.
#CXXFLAGS+= -Wmissing-format-attribute
# Disable RTTI and exceptions, and enabled checking of pointers returned by "new"
# Disable RTTI, and enable checking of pointers returned by "new"
CXXFLAGS+= -fno-exceptions -fcheck-new
# There is a nice extra warning that flags variables that are potentially

View File

@ -226,7 +226,5 @@ DIST_FILES_THEMES:=$(addprefix $(srcdir)/gui/themes/,modern.zip)
DIST_FILES_ENGINEDATA=
DIST_FILES_ENGINEDATA:=$(addprefix $(srcdir)/dists/engine-data/,$(DIST_FILES_ENGINEDATA))
# Plugin files
DIST_FILES_PLUGINS:=$(addprefix $(srcdir)/,$(PLUGINS))
.PHONY: all clean distclean plugins dist-src

View File

@ -66,19 +66,23 @@ static const char HELP_STRING[] =
" -c, --config=CONFIG Use alternate configuration file\n"
" -p, --path=PATH Path to where the game is installed\n"
" -f, --fullscreen Force full-screen mode\n"
" -q, --language=LANG Select language (en,de,fr,it,pt,es,jp,zh,kr,se,gb,\n"
" hb,ru,cz)\n"
" -F, --no-fullscreen Force windowed mode\n"
" --gui-theme=THEME Select GUI theme\n"
" --themepath=PATH Path to where GUI themes are stored\n"
" --list-themes Display list of all usable GUI themes\n"
" -e, --music-driver=MODE Select music driver\n"
" -e, --music-driver=MODE Select music driver (see README for details)\n"
" -q, --language=LANG Select language (en,de,fr,it,pt,es,jp,zh,kr,se,gb,\n"
" hb,ru,cz)\n"
" -m, --music-volume=NUM Set the music volume, 0-127 (default: 127)\n"
" -s, --sfx-volume=NUM Set the sfx volume, 0-127 (default: 127)\n"
" -r, --speech-volume=NUM Set the speech volume, 0-127 (default: 127)\n"
" --speech-mode=NUM Set the mode of speech 1-Text only, 2-Speech Only, 3-Speech and Text\n"
" --soft-renderer=BOOL Set the turn on/off software 3D renderer: true/false\n"
" --midi-gain=NUM Set the gain for MIDI playback, 0-1000 (default:\n"
" 100) (only supported by some MIDI drivers)\n"
" -d, --debuglevel=NUM Set debug verbosity level\n"
" --debugflags=FLAGS Enables engine specific debug flags\n"
" --debugflags=FLAGS Enable engine specific debug flags\n"
" (separated by commas)\n"
"\n"
" --savepath=PATH Path to where savegames are stored\n"
" --extrapath=PATH Extra path to additional game data\n"
" --soundfont=FILE Select the SoundFont for MIDI playback (only\n"
@ -89,8 +93,10 @@ static const char HELP_STRING[] =
" --output-rate=RATE Select output sample rate in Hz (e.g. 22050)\n"
" --opl-driver=DRIVER Select AdLib (OPL) emulator (db, mame)\n"
" --show-fps=BOOL Set the turn on/off display FPS info: true/false\n"
" --soft-renderer=BOOL Set the turn on/off software 3D renderer: true/false\n"
"\n"
" --dimuse-tempo=NUM Set internal Digital iMuse tempo (10 - 100) per second\n"
" (default: 10)\n"
;
#endif
@ -116,26 +122,37 @@ static void usage(const char *s, ...) {
void registerDefaults() {
ConfMan.registerDefault("platform", Common::kPlatformPC);
ConfMan.registerDefault("language", "en");
ConfMan.registerDefault("autosave_period", 5 * 60); // By default, trigger autosave every 5 minutes
// Graphics
ConfMan.registerDefault("fullscreen", false);
ConfMan.registerDefault("soft_renderer", "true");
ConfMan.registerDefault("fullscreen", "false");
ConfMan.registerDefault("show_fps", "false");
// Sound & Music
ConfMan.registerDefault("music_volume", 127);
ConfMan.registerDefault("sfx_volume", 127);
ConfMan.registerDefault("speech_volume", 127);
ConfMan.registerDefault("speech_mode", "3");
ConfMan.registerDefault("multi_midi", false);
ConfMan.registerDefault("native_mt32", false);
ConfMan.registerDefault("enable_gs", false);
ConfMan.registerDefault("midi_gain", 100);
ConfMan.registerDefault("path", ".");
// Game specific
ConfMan.registerDefault("path", "");
ConfMan.registerDefault("platform", Common::kPlatformPC);
ConfMan.registerDefault("language", "en");
ConfMan.registerDefault("autosave_period", 5 * 60); // By default, trigger autosave every 5 minutes
ConfMan.registerDefault("soft_renderer", "true");
ConfMan.registerDefault("fullscreen", "false");
ConfMan.registerDefault("show_fps", "false");
ConfMan.registerDefault("dimuse_tempo", 10);
// Miscellaneous
ConfMan.registerDefault("confirm_exit", false);
ConfMan.registerDefault("disable_sdl_parachute", false);
@ -397,10 +414,10 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_LONG_OPTION("text-speed")
END_OPTION
#ifdef ENABLE_SCUMM
DO_LONG_OPTION_INT("dimuse-tempo")
END_OPTION
#endif
DO_LONG_OPTION("speech-mode")
END_OPTION

View File

@ -87,7 +87,7 @@ static const EnginePlugin *detectPlugin() {
assert(!gameid.empty());
if (ConfMan.hasKey("gameid")) {
gameid = ConfMan.get("gameid");
// Set last selected game, that the game will be highlighted
// on RTL
ConfMan.set("lastselectedgame", ConfMan.getActiveDomainName(), Common::ConfigManager::kApplicationDomain);

View File

@ -65,6 +65,7 @@ namespace Common {
enum PluginType {
PLUGIN_TYPE_ENGINE = 0,
PLUGIN_TYPE_MUSIC,
/* PLUGIN_TYPE_SCALER, */ // TODO: Add graphics scaler plugins
PLUGIN_TYPE_MAX
};

View File

@ -100,7 +100,7 @@ private:
Common::String _recordTimeFileName;
};
} // end of namespace Common
} // End of namespace Common
#endif

View File

@ -27,15 +27,11 @@
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "engines/engine.h"
#include <stdarg.h> // For va_list etc.
#ifdef __PLAYSTATION2__
// for those replaced fopen/fread/etc functions
typedef unsigned long uint64;
typedef signed long int64;
#include "backends/platform/ps2/fileio.h"
#define fputs(str, file) ps2_fputs(str, file)
@ -52,16 +48,14 @@
// TODO: Move gDebugLevel into namespace Common.
int gDebugLevel = -1;
namespace Common {
namespace {
typedef HashMap<String, DebugChannel, IgnoreCase_Hash, IgnoreCase_EqualTo> DebugLevelMap;
typedef HashMap<String, DebugChannel, IgnoreCase_Hash, IgnoreCase_EqualTo> DebugChannelMap;
static DebugLevelMap gDebugLevels;
static uint32 gDebugLevelsEnabled = 0;
static DebugChannelMap gDebugChannels;
static uint32 gDebugChannelsEnabled = 0;
struct DebugLevelComperator {
bool operator()(const DebugChannel &l, const DebugChannel &r) {
@ -69,27 +63,27 @@ struct DebugLevelComperator {
}
};
}
} // end of anonymous namespace
bool addDebugChannel(uint32 level, const String &name, const String &description) {
if (gDebugLevels.contains(name)) {
warning("Duplicate declaration of engine debug level '%s'", name.c_str());
}
gDebugLevels[name] = DebugChannel(level, name, description);
bool addDebugChannel(uint32 channel, const String &name, const String &description) {
if (gDebugChannels.contains(name))
warning("Duplicate declaration of engine debug channel '%s'", name.c_str());
gDebugChannels[name] = DebugChannel(channel, name, description);
return true;
}
void clearAllDebugChannels() {
gDebugLevelsEnabled = 0;
gDebugLevels.clear();
gDebugChannelsEnabled = 0;
gDebugChannels.clear();
}
bool enableDebugChannel(const String &name) {
DebugLevelMap::iterator i = gDebugLevels.find(name);
DebugChannelMap::iterator i = gDebugChannels.find(name);
if (i != gDebugLevels.end()) {
gDebugLevelsEnabled |= i->_value.level;
if (i != gDebugChannels.end()) {
gDebugChannelsEnabled |= i->_value.channel;
i->_value.enabled = true;
return true;
@ -99,10 +93,10 @@ bool enableDebugChannel(const String &name) {
}
bool disableDebugChannel(const String &name) {
DebugLevelMap::iterator i = gDebugLevels.find(name);
DebugChannelMap::iterator i = gDebugChannels.find(name);
if (i != gDebugLevels.end()) {
gDebugLevelsEnabled &= ~i->_value.level;
if (i != gDebugChannels.end()) {
gDebugChannelsEnabled &= ~i->_value.channel;
i->_value.enabled = false;
return true;
@ -114,19 +108,19 @@ bool disableDebugChannel(const String &name) {
DebugChannelList listDebugChannels() {
DebugChannelList tmp;
for (DebugLevelMap::iterator i = gDebugLevels.begin(); i != gDebugLevels.end(); ++i)
for (DebugChannelMap::iterator i = gDebugChannels.begin(); i != gDebugChannels.end(); ++i)
tmp.push_back(i->_value);
sort(tmp.begin(), tmp.end(), DebugLevelComperator());
return tmp;
}
bool isDebugChannelEnabled(uint32 level) {
bool isDebugChannelEnabled(uint32 channel) {
// Debug level 11 turns on all special debug level messages
if (gDebugLevel == 11)
return true;
// return gDebugLevelsEnabled & (1 << level);
return gDebugLevelsEnabled & level;
else
return (gDebugChannelsEnabled & channel) != 0;
}
bool isDebugChannelEnabled(const String &name) {
@ -135,10 +129,11 @@ bool isDebugChannelEnabled(const String &name) {
return true;
// Search for the debug level with the given name and check if it is enabled
DebugLevelMap::iterator i = gDebugLevels.find(name);
if (i != gDebugLevels.end())
DebugChannelMap::iterator i = gDebugChannels.find(name);
if (i != gDebugChannels.end())
return i->_value.enabled;
return false;
else
return false;
}
@ -224,7 +219,7 @@ void debugC(int level, uint32 debugChannels, const char *s, ...) {
// Debug level 11 turns on all special debug level messages
if (gDebugLevel != 11)
if (level > gDebugLevel || !(Common::gDebugLevelsEnabled & debugChannels))
if (level > gDebugLevel || !(Common::gDebugChannelsEnabled & debugChannels))
return;
va_start(va, s);
@ -237,7 +232,7 @@ void debugCN(int level, uint32 debugChannels, const char *s, ...) {
// Debug level 11 turns on all special debug level messages
if (gDebugLevel != 11)
if (level > gDebugLevel || !(Common::gDebugLevelsEnabled & debugChannels))
if (level > gDebugLevel || !(Common::gDebugChannelsEnabled & debugChannels))
return;
va_start(va, s);
@ -250,7 +245,7 @@ void debugC(uint32 debugChannels, const char *s, ...) {
// Debug level 11 turns on all special debug level messages
if (gDebugLevel != 11)
if (!(Common::gDebugLevelsEnabled & debugChannels))
if (!(Common::gDebugChannelsEnabled & debugChannels))
return;
va_start(va, s);
@ -263,7 +258,7 @@ void debugCN(uint32 debugChannels, const char *s, ...) {
// Debug level 11 turns on all special debug level messages
if (gDebugLevel != 11)
if (!(Common::gDebugLevelsEnabled & debugChannels))
if (!(Common::gDebugChannelsEnabled & debugChannels))
return;
va_start(va, s);

View File

@ -35,42 +35,58 @@ namespace Common {
struct DebugChannel {
DebugChannel() : level(0), enabled(false) {}
DebugChannel(uint32 l, const String &n, const String &d)
: name(n), description(d), level(l), enabled(false) {}
DebugChannel() : channel(0), enabled(false) {}
DebugChannel(uint32 c, const String &n, const String &d)
: name(n), description(d), channel(c), enabled(false) {}
String name;
String description;
uint32 level;
uint32 channel;
bool enabled;
};
/**
* Adds a engine debug level.
* @param level the level flag (should be OR-able i.e. first one should be 1 than 2,4,...)
* Adds a debug channel.
*
* A debug channel is considered roughly similar to what our debug levels described by
* gDebugLevel try to achieve:
*
* Debug channels should only affect the display of additional debug output, based on
* their state. That is if they are enabled, channel specific debug messages should
* be shown. If they are disabled on the other hand, those messages will be hidden.
*
* @see gDebugLevel.
*
* Note that we have debug* functions which depend both on the debug level set and
* specific debug channels. Those functions will only show output, when *both* criteria
* are satisfied.
*
* @param channel the channel flag (should be OR-able i.e. first one should be 1 then 2, 4, etc.)
* @param name the option name which is used in the debugger/on the command line to enable
* this special debug level (case will be ignored)
* this special debug level (case will be ignored)
* @param description the description which shows up in the debugger
* @return true on success false on failure
*/
bool addDebugChannel(uint32 level, const String &name, const String &description);
bool addDebugChannel(uint32 channel, const String &name, const String &description);
/**
* Resets all engine debug levels.
* Resets all engine specific debug channels.
*/
void clearAllDebugChannels();
/**
* Enables an engine debug level.
* @param name the name of the debug level to enable
* Enables an debug channel.
*
* @param name the name of the debug channel to enable
* @return true on success, false on failure
*/
bool enableDebugChannel(const String &name);
/**
* Disables an engine debug level
* @param name the name of the debug level to disable
* Disables an debug channel.
*
* @param name the name of the debug channel to disable
* @return true on success, false on failure
*/
bool disableDebugChannel(const String &name);
@ -80,19 +96,20 @@ bool disableDebugChannel(const String &name);
typedef List<DebugChannel> DebugChannelList;
/**
* Lists all debug levels
* @return returns a arry with all debug levels
* Lists all engine specific debug channels.
*
* @return returns a arry with all debug channels
*/
DebugChannelList listDebugChannels();
/**
* Test whether the given debug level is enabled.
* Test whether the given debug channel is enabled.
*/
bool isDebugChannelEnabled(uint32 level);
bool isDebugChannelEnabled(uint32 channel);
/**
* Test whether the given debug level is enabled.
* Test whether the given debug channel is enabled.
*/
bool isDebugChannelEnabled(const String &name);
@ -111,10 +128,10 @@ void setDebugOutputFormatter(OutputFormatter f);
inline void debug(const char *s, ...) {}
inline void debug(int level, const char *s, ...) {}
inline void debugN(int level, const char *s, ...) {}
inline void debugC(int level, uint32 engine_level, const char *s, ...) {}
inline void debugC(uint32 engine_level, const char *s, ...) {}
inline void debugCN(int level, uint32 engine_level, const char *s, ...) {}
inline void debugCN(uint32 engine_level, const char *s, ...) {}
inline void debugC(int level, uint32 engineChannel, const char *s, ...) {}
inline void debugC(uint32 engineChannel, const char *s, ...) {}
inline void debugCN(int level, uint32 engineChannel, const char *s, ...) {}
inline void debugCN(uint32 engineChannel, const char *s, ...) {}
#else

View File

@ -44,7 +44,7 @@
* FROM_??_??(a) - convert LE/BE value v to native
* CONSTANT_??_??(a) - convert LE/BE value v to native, implemented as macro.
* Use with compiletime-constants only, the result will be a compiletime-constant aswell.
* Unlike most other functions these can be used for eg. switch-case labels
* Unlike most other functions these can be used for eg. switch-case labels
*/
// Sanity check
@ -103,7 +103,7 @@
}
// generic fallback
#else
#else
inline uint32 SWAP_BYTES_32(uint32 a) {
const uint16 low = (uint16)a, high = (uint16)(a >> 16);
@ -184,7 +184,7 @@
*(uint32 *)(ptr) = value;
}
// test for GCC >= 4.0. these implementations will automatically use CPU-specific
// test for GCC >= 4.0. these implementations will automatically use CPU-specific
// instructions for unaligned data when they are available (eg. MIPS)
#elif defined(__GNUC__) && (__GNUC__ >= 4)
@ -326,7 +326,7 @@
inline void WRITE_BE_UINT32(void *ptr, uint32 value) {
WRITE_UINT32(ptr, SWAP_BYTES_32(value));
}
# endif // if defined(SYSTEM_NEED_ALIGNMENT)
#elif defined(SYSTEM_BIG_ENDIAN)
@ -394,7 +394,7 @@
inline void WRITE_LE_UINT32(void *ptr, uint32 value) {
WRITE_UINT32(ptr, SWAP_BYTES_32(value));
}
# endif // if defined(SYSTEM_NEED_ALIGNMENT)
#endif // if defined(SYSTEM_LITTLE_ENDIAN)

View File

@ -40,9 +40,9 @@
namespace Common {
// The sgi IRIX MIPSpro Compiler has difficulties with nested templates.
// The sgi IRIX MIPSpro Compiler has difficulties with nested templates.
// This and the other __sgi conditionals below work around these problems.
#if defined(__sgi) && !defined(__GNUC__)
#ifdef __sgi
template<class T> class IteratorImpl;
#endif
@ -131,7 +131,7 @@ public:
int lookupAndCreateIfMissing(const Key &key);
void expandStorage(uint newCapacity);
#if !defined(__sgi) || defined(__GNUC__)
#ifndef __sgi
template<class T> friend class IteratorImpl;
#endif
@ -141,7 +141,7 @@ public:
template<class NodeType>
class IteratorImpl {
friend class HashMap;
#if defined(__sgi) && !defined(__GNUC__)
#ifdef __sgi
template<class T> friend class Common::IteratorImpl;
#else
template<class T> friend class IteratorImpl;

View File

@ -1,334 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#include "common/libz.h"
#include "common/util.h"
#if defined(USE_ZLIB)
#ifdef __SYMBIAN32__
#include <zlib\zlib.h>
#else
#include <zlib.h>
#endif
#if ZLIB_VERNUM < 0x1204
#error Version 1.2.0.4 or newer of zlib is required for this code
#endif
#endif
namespace Common {
#if defined(USE_ZLIB)
bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen) {
return Z_OK == ::uncompress(dst, dstLen, src, srcLen);
}
/**
* A simple wrapper class which can be used to wrap around an arbitrary
* other SeekableReadStream and will then provide on-the-fly decompression support.
* Assumes the compressed data to be in gzip format.
*/
class GZipReadStream : public Common::SeekableReadStream {
protected:
enum {
BUFSIZE = 16384 // 1 << MAX_WBITS
};
byte _buf[BUFSIZE];
Common::SeekableReadStream *_wrapped;
z_stream _stream;
int _zlibErr;
uint32 _pos;
uint32 _origSize;
bool _eos;
public:
GZipReadStream(Common::SeekableReadStream *w) : _wrapped(w) {
assert(w != 0);
_stream.zalloc = Z_NULL;
_stream.zfree = Z_NULL;
_stream.opaque = Z_NULL;
// Verify file header is correct
w->seek(0, SEEK_SET);
uint16 header = w->readUint16BE();
assert(header == 0x1F8B ||
((header & 0x0F00) == 0x0800 && header % 31 == 0));
if (header == 0x1F8B) {
// Retrieve the original file size
w->seek(-4, SEEK_END);
_origSize = w->readUint32LE();
} else {
// Original size not available in zlib format
_origSize = 0;
}
_pos = 0;
w->seek(0, SEEK_SET);
_eos = false;
// Adding 32 to windowBits indicates to zlib that it is supposed to
// automatically detect whether gzip or zlib headers are used for
// the compressed file. This feature was added in zlib 1.2.0.4,
// released 10 August 2003.
// Note: This is *crucial* for savegame compatibility, do *not* remove!
_zlibErr = inflateInit2(&_stream, MAX_WBITS + 32);
if (_zlibErr != Z_OK)
return;
// Setup input buffer
_stream.next_in = _buf;
_stream.avail_in = 0;
}
~GZipReadStream() {
inflateEnd(&_stream);
delete _wrapped;
}
bool err() const { return (_zlibErr != Z_OK) && (_zlibErr != Z_STREAM_END); }
void clearErr() {
// only reset _eos; I/O errors are not recoverable
_eos = false;
}
uint32 read(void *dataPtr, uint32 dataSize) {
_stream.next_out = (byte *)dataPtr;
_stream.avail_out = dataSize;
// Keep going while we get no error
while (_zlibErr == Z_OK && _stream.avail_out) {
if (_stream.avail_in == 0 && !_wrapped->eos()) {
// If we are out of input data: Read more data, if available.
_stream.next_in = _buf;
_stream.avail_in = _wrapped->read(_buf, BUFSIZE);
}
_zlibErr = inflate(&_stream, Z_NO_FLUSH);
}
// Update the position counter
_pos += dataSize - _stream.avail_out;
if (_zlibErr == Z_STREAM_END && _stream.avail_out > 0)
_eos = true;
return dataSize - _stream.avail_out;
}
bool eos() const {
return _eos;
}
int32 pos() const {
return _pos;
}
int32 size() const {
return _origSize;
}
bool seek(int32 offset, int whence = SEEK_SET) {
int32 newPos = 0;
assert(whence != SEEK_END); // SEEK_END not supported
switch (whence) {
case SEEK_SET:
newPos = offset;
break;
case SEEK_CUR:
newPos = _pos + offset;
}
assert(newPos >= 0);
if ((uint32)newPos < _pos) {
// To search backward, we have to restart the whole decompression
// from the start of the file. A rather wasteful operation, best
// to avoid it. :/
#if DEBUG
warning("Backward seeking in GZipReadStream detected");
#endif
_pos = 0;
_wrapped->seek(0, SEEK_SET);
_zlibErr = inflateReset(&_stream);
if (_zlibErr != Z_OK)
return false; // FIXME: STREAM REWRITE
_stream.next_in = _buf;
_stream.avail_in = 0;
}
offset = newPos - _pos;
// Skip the given amount of data (very inefficient if one tries to skip
// huge amounts of data, but usually client code will only skip a few
// bytes, so this should be fine.
byte tmpBuf[1024];
while (!err() && offset > 0) {
offset -= read(tmpBuf, MIN((int32)sizeof(tmpBuf), offset));
}
_eos = false;
return true; // FIXME: STREAM REWRITE
}
};
/**
* A simple wrapper class which can be used to wrap around an arbitrary
* other WriteStream and will then provide on-the-fly compression support.
* The compressed data is written in the gzip format.
*/
class GZipWriteStream : public Common::WriteStream {
protected:
enum {
BUFSIZE = 16384 // 1 << MAX_WBITS
};
byte _buf[BUFSIZE];
Common::WriteStream *_wrapped;
z_stream _stream;
int _zlibErr;
void processData(int flushType) {
// This function is called by both write() and finalize().
while (_zlibErr == Z_OK && (_stream.avail_in || flushType == Z_FINISH)) {
if (_stream.avail_out == 0) {
if (_wrapped->write(_buf, BUFSIZE) != BUFSIZE) {
_zlibErr = Z_ERRNO;
break;
}
_stream.next_out = _buf;
_stream.avail_out = BUFSIZE;
}
_zlibErr = deflate(&_stream, flushType);
}
}
public:
GZipWriteStream(Common::WriteStream *w) : _wrapped(w) {
assert(w != 0);
_stream.zalloc = Z_NULL;
_stream.zfree = Z_NULL;
_stream.opaque = Z_NULL;
// Adding 16 to windowBits indicates to zlib that it is supposed to
// write gzip headers. This feature was added in zlib 1.2.0.4,
// released 10 August 2003.
// Note: This is *crucial* for savegame compatibility, do *not* remove!
_zlibErr = deflateInit2(&_stream,
Z_DEFAULT_COMPRESSION,
Z_DEFLATED,
MAX_WBITS + 16,
8,
Z_DEFAULT_STRATEGY);
assert(_zlibErr == Z_OK);
_stream.next_out = _buf;
_stream.avail_out = BUFSIZE;
_stream.avail_in = 0;
_stream.next_in = 0;
}
~GZipWriteStream() {
finalize();
deflateEnd(&_stream);
delete _wrapped;
}
bool err() const {
// CHECKME: does Z_STREAM_END make sense here?
return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->err();
}
void clearErr() {
// Note: we don't reset the _zlibErr here, as it is not
// clear in general how
_wrapped->clearErr();
}
void finalize() {
if (_zlibErr != Z_OK)
return;
// Process whatever remaining data there is.
processData(Z_FINISH);
// Since processData only writes out blocks of size BUFSIZE,
// we may have to flush some stragglers.
uint remainder = BUFSIZE - _stream.avail_out;
if (remainder > 0) {
if (_wrapped->write(_buf, remainder) != remainder) {
_zlibErr = Z_ERRNO;
}
}
// Finalize the wrapped savefile, too
_wrapped->finalize();
}
uint32 write(const void *dataPtr, uint32 dataSize) {
if (err())
return 0;
// Hook in the new data ...
// Note: We need to make a const_cast here, as zlib is not aware
// of the const keyword.
_stream.next_in = const_cast<byte *>((const byte *)dataPtr);
_stream.avail_in = dataSize;
// ... and flush it to disk
processData(Z_NO_FLUSH);
return dataSize - _stream.avail_in;
}
};
#endif // USE_ZLIB
Common::SeekableReadStream *wrapCompressedReadStream(Common::SeekableReadStream *toBeWrapped) {
#if defined(USE_ZLIB)
if (toBeWrapped) {
uint16 header = toBeWrapped->readUint16BE();
bool isCompressed = (header == 0x1F8B ||
((header & 0x0F00) == 0x0800 &&
header % 31 == 0));
toBeWrapped->seek(-2, SEEK_CUR);
if (isCompressed)
return new GZipReadStream(toBeWrapped);
}
#endif
return toBeWrapped;
}
Common::WriteStream *wrapCompressedWriteStream(Common::WriteStream *toBeWrapped) {
#if defined(USE_ZLIB)
if (toBeWrapped)
return new GZipWriteStream(toBeWrapped);
#endif
return toBeWrapped;
}
} // End of namespace Common

View File

@ -1,72 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#ifndef COMMON_ZLIB_H
#define COMMON_ZLIB_H
#include "common/sys.h"
#include "common/stream.h"
namespace Common {
#if defined(USE_ZLIB)
/**
* Thin wrapper around zlib's uncompress() function. This wrapper makes
* it possible to uncompress data in engines without being forced to link
* them against zlib, thus simplifying the build system.
*
* @return true on success (i.e. Z_OK), false otherwise
*/
bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen);
#endif
/**
* Take an arbitrary SeekableReadStream and wrap it in a custom stream which
* provides transparent on-the-fly decompression. Assumes the data it
* retrieves from the wrapped stream to be either uncompressed or in gzip
* format. In the former case, the original stream is returned unmodified
* (and in particular, not wrapped).
*
* It is safe to call this with a NULL parameter (in this case, NULL is
* returned).
*/
Common::SeekableReadStream *wrapCompressedReadStream(Common::SeekableReadStream *toBeWrapped);
/**
* Take an arbitrary WriteStream and wrap it in a custom stream which provides
* transparent on-the-fly compression. The compressed data is written in the
* gzip format, unless ZLIB support has been disabled, in which case the given
* stream is returned unmodified (and in particular, not wrapped).
*
* It is safe to call this with a NULL parameter (in this case, NULL is
* returned).
*/
Common::WriteStream *wrapCompressedWriteStream(Common::WriteStream *toBeWrapped);
} // End of namespace Common
#endif

View File

@ -4,23 +4,23 @@ MODULE_OBJS := \
archive.o \
config-file.o \
config-manager.o \
textconsole.o \
debug.o \
EventDispatcher.o \
EventRecorder.o \
file.o \
fs.o \
hashmap.o \
libz.o \
memorypool.o \
md5.o \
mutex.o \
str.o \
stream.o \
textconsole.o \
util.o \
system.o \
unzip.o \
xmlparser.o
xmlparser.o \
zlib.o
# Include common rules
include $(srcdir)/rules.mk

View File

@ -180,15 +180,15 @@ public:
_pointer = 0;
}
template<class T2>
bool operator==(const Common::SharedPtr<T2> &r) const {
return _pointer == r.get();
}
template<class T2>
bool operator==(const Common::SharedPtr<T2> &r) const {
return _pointer == r.get();
}
template<class T2>
bool operator!=(const Common::SharedPtr<T2> &r) const {
return _pointer != r.get();
}
template<class T2>
bool operator!=(const Common::SharedPtr<T2> &r) const {
return _pointer != r.get();
}
/**
* Returns the number of references to the assigned pointer.
@ -216,6 +216,6 @@ private:
T *_pointer;
};
} // end of namespace Common
} // End of namespace Common
#endif

View File

@ -37,7 +37,7 @@
namespace Common {
MemoryPool *g_refCountPool = 0; // FIXME: This is never freed right now
MemoryPool *g_refCountPool = 0; // FIXME: This is never freed right now
static uint32 computeCapacity(uint32 len) {
// By default, for the capacity we use the next multiple of 32
@ -84,7 +84,7 @@ void String::initWithCStr(const char *str, uint32 len) {
}
String::String(const String &str)
: _size(str._size) {
: _size(str._size) {
if (str.isStorageIntern()) {
// String in internal storage: just copy it
memcpy(_storage, str._storage, _builtinCapacity);
@ -100,7 +100,7 @@ String::String(const String &str)
}
String::String(char c)
: _size(0), _str(_storage) {
: _size(0), _str(_storage) {
_storage[0] = c;
_storage[1] = 0;
@ -219,7 +219,7 @@ void String::decRefCount(int *oldRefCount) {
}
}
String& String::operator =(const char *str) {
String &String::operator=(const char *str) {
uint32 len = strlen(str);
ensureCapacity(len, false);
_size = len;
@ -227,7 +227,7 @@ String& String::operator =(const char *str) {
return *this;
}
String &String::operator =(const String &str) {
String &String::operator=(const String &str) {
if (&str == this)
return *this;
@ -249,7 +249,7 @@ String &String::operator =(const String &str) {
return *this;
}
String& String::operator =(char c) {
String &String::operator=(char c) {
decRefCount(_extern._refCount);
_str = _storage;
_size = 1;
@ -258,7 +258,7 @@ String& String::operator =(char c) {
return *this;
}
String &String::operator +=(const char *str) {
String &String::operator+=(const char *str) {
if (_str <= str && str <= _str + _size)
return operator+=(Common::String(str));
@ -272,7 +272,7 @@ String &String::operator +=(const char *str) {
return *this;
}
String &String::operator +=(const String &str) {
String &String::operator+=(const String &str) {
if (&str == this)
return operator+=(Common::String(str));
@ -286,7 +286,7 @@ String &String::operator +=(const String &str) {
return *this;
}
String &String::operator +=(char c) {
String &String::operator+=(char c) {
ensureCapacity(_size + 1, true);
_str[_size++] = c;
@ -363,7 +363,7 @@ void String::deleteChar(uint32 p) {
makeUnique();
while (p++ < _size)
_str[p-1] = _str[p];
_str[p - 1] = _str[p];
_size--;
}
@ -388,7 +388,7 @@ void String::insertChar(char c, uint32 p) {
ensureCapacity(_size + 1, true);
_size++;
for (uint32 i = _size; i > p; --i)
_str[i] = _str[i-1];
_str[i] = _str[i - 1];
_str[p] = c;
}
@ -411,8 +411,8 @@ void String::trim() {
makeUnique();
// Trim trailing whitespace
while (_size >= 1 && isspace(_str[_size-1]))
_size--;
while (_size >= 1 && isspace(_str[_size - 1]))
--_size;
_str[_size] = 0;
// Trim leading whitespace
@ -449,7 +449,7 @@ String String::printf(const char *fmt, ...) {
int size = _builtinCapacity;
do {
size *= 2;
output.ensureCapacity(size-1, false);
output.ensureCapacity(size - 1, false);
assert(!output.isStorageIntern());
size = output._extern._capacity;
@ -477,16 +477,16 @@ String String::printf(const char *fmt, ...) {
#pragma mark -
bool String::operator ==(const String &x) const {
bool String::operator==(const String &x) const {
return equals(x);
}
bool String::operator ==(const char *x) const {
bool String::operator==(const char *x) const {
assert(x != 0);
return equals(x);
}
bool String::operator !=(const String &x) const {
bool String::operator!=(const String &x) const {
return !equals(x);
}
@ -495,29 +495,29 @@ bool String::operator !=(const char *x) const {
return !equals(x);
}
bool String::operator < (const String &x) const {
bool String::operator<(const String &x) const {
return compareTo(x) < 0;
}
bool String::operator <= (const String &x) const {
bool String::operator<=(const String &x) const {
return compareTo(x) <= 0;
}
bool String::operator > (const String &x) const {
bool String::operator>(const String &x) const {
return compareTo(x) > 0;
}
bool String::operator >= (const String &x) const {
bool String::operator>=(const String &x) const {
return compareTo(x) >= 0;
}
#pragma mark -
bool operator == (const char* y, const String &x) {
bool operator==(const char* y, const String &x) {
return (x == y);
}
bool operator != (const char* y, const String &x) {
bool operator!=(const char* y, const String &x) {
return x != y;
}
@ -561,31 +561,31 @@ int String::compareToIgnoreCase(const char *x) const {
#pragma mark -
String operator +(const String &x, const String &y) {
String operator+(const String &x, const String &y) {
String temp(x);
temp += y;
return temp;
}
String operator +(const char *x, const String &y) {
String operator+(const char *x, const String &y) {
String temp(x);
temp += y;
return temp;
}
String operator +(const String &x, const char *y) {
String operator+(const String &x, const char *y) {
String temp(x);
temp += y;
return temp;
}
String operator +(char x, const String &y) {
String operator+(char x, const String &y) {
String temp(x);
temp += y;
return temp;
}
String operator +(const String &x, char y) {
String operator+(const String &x, char y) {
String temp(x);
temp += y;
return temp;

View File

@ -54,20 +54,20 @@ protected:
* than 8 makes no sense, since that's the size of member _extern
* (on 32 bit machines; 12 bytes on systems with 64bit pointers).
*/
static const uint32 _builtinCapacity = 32 - sizeof(uint32) - sizeof(char*);
static const uint32 _builtinCapacity = 32 - sizeof(uint32) - sizeof(char *);
/**
* Length of the string. Stored to avoid having to call strlen
* a lot. Yes, we limit ourselves to strings shorter than 4GB --
* on purpose :-).
*/
uint32 _size;
uint32 _size;
/**
* Pointer to the actual string storage. Either points to _storage,
* or to a block allocated on the heap via malloc.
*/
char *_str;
char *_str;
union {
@ -81,7 +81,7 @@ protected:
*/
struct {
mutable int *_refCount;
uint32 _capacity;
uint32 _capacity;
} _extern;
};
@ -110,32 +110,32 @@ public:
~String();
String &operator =(const char *str);
String &operator =(const String &str);
String &operator =(char c);
String &operator +=(const char *str);
String &operator +=(const String &str);
String &operator +=(char c);
String &operator=(const char *str);
String &operator=(const String &str);
String &operator=(char c);
String &operator+=(const char *str);
String &operator+=(const String &str);
String &operator+=(char c);
bool operator ==(const String &x) const;
bool operator ==(const char *x) const;
bool operator !=(const String &x) const;
bool operator !=(const char *x) const;
bool operator==(const String &x) const;
bool operator==(const char *x) const;
bool operator!=(const String &x) const;
bool operator!=(const char *x) const;
bool operator <(const String &x) const;
bool operator <=(const String &x) const;
bool operator >(const String &x) const;
bool operator >=(const String &x) const;
bool operator<(const String &x) const;
bool operator<=(const String &x) const;
bool operator>(const String &x) const;
bool operator>=(const String &x) const;
bool equals(const String &x) const;
bool equalsIgnoreCase(const String &x) const;
int compareTo(const String &x) const; // strcmp clone
int compareToIgnoreCase(const String &x) const; // stricmp clone
int compareTo(const String &x) const; // strcmp clone
int compareToIgnoreCase(const String &x) const; // stricmp clone
bool equals(const char *x) const;
bool equalsIgnoreCase(const char *x) const;
int compareTo(const char *x) const; // strcmp clone
int compareToIgnoreCase(const char *x) const; // stricmp clone
int compareTo(const char *x) const; // strcmp clone
int compareToIgnoreCase(const char *x) const; // stricmp clone
bool hasSuffix(const String &x) const;
bool hasSuffix(const char *x) const;
@ -152,15 +152,15 @@ public:
* Taken from exult/files/listfiles.cc
*
* Token meaning:
* "*": any character, any amount of times.
* "?": any character, only once.
* "*": any character, any amount of times.
* "?": any character, only once.
*
* Example strings/patterns:
* String: monkey.s01 Pattern: monkey.s?? => true
* String: monkey.s101 Pattern: monkey.s?? => false
* String: monkey.s99 Pattern: monkey.s?1 => false
* String: monkey.s101 Pattern: monkey.s* => true
* String: monkey.s99 Pattern: monkey.s*1 => false
* String: monkey.s01 Pattern: monkey.s?? => true
* String: monkey.s101 Pattern: monkey.s?? => false
* String: monkey.s99 Pattern: monkey.s?1 => false
* String: monkey.s101 Pattern: monkey.s* => true
* String: monkey.s99 Pattern: monkey.s*1 => false
*
* @param str Text to be matched against the given pattern.
* @param pat Glob pattern.
@ -173,11 +173,11 @@ public:
bool matchString(const String &pat, bool ignoreCase = false, bool pathMode = false) const;
inline const char *c_str() const { return _str; }
inline uint size() const { return _size; }
inline const char *c_str() const { return _str; }
inline uint size() const { return _size; }
inline bool empty() const { return (_size == 0); }
char lastChar() const { return (_size > 0) ? _str[_size-1] : 0; }
inline bool empty() const { return (_size == 0); }
char lastChar() const { return (_size > 0) ? _str[_size - 1] : 0; }
char operator[](int idx) const {
assert(_str && idx >= 0 && idx < (int)_size);
@ -222,19 +222,19 @@ public:
typedef char * iterator;
typedef const char * const_iterator;
iterator begin() {
iterator begin() {
return _str;
}
iterator end() {
iterator end() {
return begin() + size();
}
const_iterator begin() const {
const_iterator begin() const {
return _str;
}
const_iterator end() const {
const_iterator end() const {
return begin() + size();
}
@ -247,17 +247,17 @@ protected:
};
// Append two strings to form a new (temp) string
String operator +(const String &x, const String &y);
String operator+(const String &x, const String &y);
String operator +(const char *x, const String &y);
String operator +(const String &x, const char *y);
String operator+(const char *x, const String &y);
String operator+(const String &x, const char *y);
String operator +(const String &x, char y);
String operator +(char x, const String &y);
String operator+(const String &x, char y);
String operator+(char x, const String &y);
// Some useful additional comparison operators for Strings
bool operator == (const char *x, const String &y);
bool operator != (const char *x, const String &y);
bool operator==(const char *x, const String &y);
bool operator!=(const char *x, const String &y);
// Utility functions to remove leading and trailing whitespaces
extern char *ltrim(char *t);
@ -269,9 +269,9 @@ extern char *trim(char *t);
* Returns the last component of a given path.
*
* Examples:
* /foo/bar.txt would return 'bar.txt'
* /foo/bar/ would return 'bar'
* /foo/./bar// would return 'bar'
* /foo/bar.txt would return 'bar.txt'
* /foo/bar/ would return 'bar'
* /foo/./bar// would return 'bar'
*
* @param path the path of which we want to know the last component
* @param sep character used to separate path components
@ -287,9 +287,9 @@ Common::String lastPathComponent(const Common::String &path, const char sep);
*
* @todo remove double dot components: /foo/baz/../bar -> /foo/bar
*
* @param path the path to normalize
* @param sep the separator token (usually '/' on Unix-style systems, or '\\' on Windows based stuff)
* @return the normalized path
* @param path the path to normalize
* @param sep the separator token (usually '/' on Unix-style systems, or '\\' on Windows based stuff)
* @return the normalized path
*/
Common::String normalizePath(const Common::String &path, const char sep);
@ -299,15 +299,15 @@ Common::String normalizePath(const Common::String &path, const char sep);
* Taken from exult/files/listfiles.cc
*
* Token meaning:
* "*": any character, any amount of times.
* "?": any character, only once.
* "*": any character, any amount of times.
* "?": any character, only once.
*
* Example strings/patterns:
* String: monkey.s01 Pattern: monkey.s?? => true
* String: monkey.s101 Pattern: monkey.s?? => false
* String: monkey.s99 Pattern: monkey.s?1 => false
* String: monkey.s101 Pattern: monkey.s* => true
* String: monkey.s99 Pattern: monkey.s*1 => false
* String: monkey.s01 Pattern: monkey.s?? => true
* String: monkey.s101 Pattern: monkey.s?? => false
* String: monkey.s99 Pattern: monkey.s?1 => false
* String: monkey.s101 Pattern: monkey.s* => true
* String: monkey.s99 Pattern: monkey.s*1 => false
*
* @param str Text to be matched against the given pattern.
* @param pat Glob pattern.
@ -321,6 +321,6 @@ bool matchString(const char *str, const char *pat, bool ignoreCase = false, bool
typedef Array<String> StringList;
} // End of namespace Common
} // End of namespace Common
#endif

View File

@ -26,9 +26,8 @@
#ifndef COMMON_STREAM_H
#define COMMON_STREAM_H
#include "common/sys.h"
#include "common/endian.h"
#include "common/types.h"
#include "common/endian.h"
namespace Common {

View File

@ -26,49 +26,91 @@
#ifndef COMMON_SYS_H
#define COMMON_SYS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <math.h>
#ifndef _MSC_VER
#include <dirent.h>
#include <unistd.h>
#if defined(_WIN32_WCE) && _WIN32_WCE < 300
#define NONSTANDARD_PORT
#endif
#ifdef _MSC_VER
#pragma once
#pragma warning( disable : 4068 ) // turn off "unknown pragma" warning
#pragma warning( disable : 4100 ) // turn off "unreferenced formal parameter" warning
#pragma warning( disable : 4127 ) // turn off "conditional expression is constant" warning
#pragma warning( disable : 4189 ) // turn off "local variable is initialized but not referenced" warning
#pragma warning( disable : 4244 ) // turn off "conversion type" warning
#pragma warning( disable : 4250 ) // turn off "inherits via dominance" warning
#pragma warning( disable : 4505 ) // turn off "unreferenced local function has been removed" warning
#pragma warning( disable : 4512 ) // turn off "assignment operator could not be generated" warning
#pragma warning( disable : 4611 ) // turn off "interaction between '_setjmp' and C++ object destruction is non-portable" warning
#pragma warning( disable : 4800 ) // turn off "forcing value to bool 'true' or 'false' (performance warning)"
#pragma warning( disable : 4996 ) // turn off "This function or variable may be unsafe" warning
#if defined(NONSTANDARD_PORT)
// Ports which need to perform #includes and #defines visible in
// virtually all the source of ScummVM should do so by providing a
// "portdefs.h" header file (and not by directly modifying this
// header file).
#include <portdefs.h>
#else // defined(NONSTANDARD_PORT)
#if defined(WIN32)
#ifdef _MSC_VER
// vsnprintf is already defined in Visual Studio 2008
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#endif
#if !defined(_WIN32_WCE)
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOGDICAPMASKS
#define OEMRESOURCE
#define NONLS
#define NOICONS
#define NOMCX
#define NOPROFILER
#define NOKANJI
#define NOSERVICE
#define NOMETAFILE
#define NOCOMM
#define NOCRYPT
#define NOIME
#define NOATOM
#define NOCTLMGR
#define NOCLIPBOARD
#define NOMEMMGR
#define NOSYSMETRICS
#define NOMENUS
#define NOOPENFILE
#define NOWH
#define NOSOUND
#define NODRAWTEXT
#endif
#if defined(ARRAYSIZE)
// VS2005beta2 introduces new stuff in winnt.h
#undef ARRAYSIZE
#endif
#endif
#if defined(__QNXNTO__)
#include <strings.h> /* For strcasecmp */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <math.h>
// vsnprintf is already defined in Visual Studio 2008
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#endif
#ifndef LOCAL_PI
#define LOCAL_PI 3.14159265358979323846
#endif
// Use config.h, generated by configure
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
// make sure we really are compiling for WIN32
#ifndef WIN32
#undef _MSC_VER
#endif
// In the following we configure various targets, in particular those
// which can't use our "configure" tool and hence don't use config.h.
//
@ -270,6 +312,8 @@
#elif defined(__PSP__)
#include <malloc.h>
#define SYSTEM_LITTLE_ENDIAN
#define SYSTEM_NEED_ALIGNMENT
@ -286,12 +330,10 @@
#define SYSTEM_NEED_ALIGNMENT
#define SYSTEM_LITTLE_ENDIAN
#include "nds/jtypes.h"
#define SYSTEM_DONT_DEFINE_TYPES
#define STRINGBUFLEN 256
#define printf(fmt, ...) consolePrintf(fmt, ##__VA_ARGS__)
// #define printf(fmt, ...) consolePrintf(fmt, ##__VA_ARGS__)
#elif defined(__WII__)
@ -308,14 +350,19 @@
// GCC specific stuff
//
#if defined(__GNUC__)
#define NORETURN __attribute__((__noreturn__))
#define PACKED_STRUCT __attribute__((packed))
#define GCC_PRINTF(x,y) __attribute__((format(printf, x, y)))
#define NORETURN_POST __attribute__((__noreturn__))
#define PACKED_STRUCT __attribute__((__packed__))
#define GCC_PRINTF(x,y) __attribute__((__format__(printf, x, y)))
#if !defined(FORCEINLINE) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define FORCEINLINE inline __attribute__((__always_inline__))
#endif
#else
#define PACKED_STRUCT
#define GCC_PRINTF(x,y)
#endif
//
// Fallbacks / default values for various special macros
//
@ -339,6 +386,10 @@
#define STRINGBUFLEN 1024
#endif
#ifndef LOCAL_PI
#define LOCAL_PI 3.14159265358979323846
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif
@ -359,4 +410,17 @@
#endif
#endif // COMMON_SYS_H
//
// Overlay color type (FIXME: shouldn't be declared here)
//
#if defined(NEWGUI_256)
// 256 color only on PalmOS
typedef byte OverlayColor;
#else
// 15/16 bit color mode everywhere else...
typedef uint16 OverlayColor;
#endif
#endif

View File

@ -32,8 +32,6 @@
#include "graphics/pixelformat.h"
typedef uint16 OverlayColor;
namespace Audio {
class Mixer;
}

View File

@ -35,8 +35,6 @@ extern bool isSmartphone();
#ifdef __PLAYSTATION2__
// for those replaced fopen/fread/etc functions
typedef unsigned long uint64;
typedef signed long int64;
#include "backends/platform/ps2/fileio.h"
#define fputs(str, file) ps2_fputs(str, file)
@ -266,7 +264,6 @@ const PlatformDescription g_platforms[] = {
{"segacd", "segacd", "sega", "SegaCD", kPlatformSegaCD},
{"windows", "win", "win", "Windows", kPlatformWindows},
{"playstation", "psx", "psx", "Sony PlayStation", kPlatformPSX},
{"playstation2", "ps2", "ps2", "Sony PlayStation 2", kPlatformPS2},
{"cdi", "cdi", "cdi", "Phillips CD-i", kPlatformCDi},
{0, 0, 0, "Default", kPlatformUnknown}

View File

@ -57,10 +57,6 @@ template<typename T> inline T CLIP (T v, T amin, T amax)
*/
template<typename T> inline void SWAP(T &a, T &b) { T tmp = a; a = b; b = tmp; }
#if defined(ARRAYSIZE)
// VS2005beta2 introduces new stuff in winnt.h
#undef ARRAYSIZE
#endif
/**
* Macro which determines the number of entries in a fixed size array.
*/
@ -226,7 +222,6 @@ enum Platform {
kPlatformWii,
kPlatformPSX,
kPlatformCDi,
kPlatformPS2,
kPlatformUnknown = -1
};

View File

@ -247,10 +247,12 @@ bool XMLParser::closeKey() {
}
bool XMLParser::parse() {
if (_stream == 0)
return parserError("XML stream not ready for reading.");
// Make sure we are at the start of the stream.
_stream->seek(0, SEEK_SET);
if (_XMLkeys == 0)
buildLayout();

893
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
@echo off
rem This batch file is used to convert MSVC8 (Visual Studio 2005) project files to MSVC9 (Visual Studio 2008) ones
rem You need the Windows version of GNU rpl
rem Get it here:
rem http://gnuwin32.sourceforge.net/packages/rpl.htm
rem Place rpl.exe from the bin folder inside the archive in the folder where
rem this batch file resides
if not exist rpl.exe goto no_rpl
echo Creating MSVC9 project files from the MSVC8 ones
copy /y msvc8\*.vcproj msvc9\
copy /y msvc8\*.sln msvc9\
copy /y msvc8\*.vsprops msvc9\
rpl -e -q "Version=\"8.00\"" "Version=\"9.00\"" msvc9\*.vcproj
rpl -e -q "Version=\"8,00\"" "Version=\"9,00\"" msvc9\*.vcproj
rpl -e -q "Keyword=\"Win32Proj\"" "Keyword=\"Win32Proj\"\n\tTargetFrameworkVersion=\"131072\"" msvc9\*.vcproj
rpl -e -q "Format Version 9.00" "Format Version 10.00" msvc9\residual.sln
rpl -e -q "Format Version 9,00" "Format Version 10,00" msvc9\residual.sln
goto the_end
:no_rpl
echo You need the Windows version of GNU rpl
echo Get it here:
echo http://gnuwin32.sourceforge.net/packages/rpl.htm
echo Place rpl.exe from the bin folder inside the archive in the folder where
echo this batch file resides
:the_end
pause

View File

@ -1,30 +0,0 @@
@echo off
rem This batch file is used to convert MSVC9 (Visual Studio 2008) project files to MSVC8 (Visual Studio 2005) ones
rem You need the Windows version of GNU rpl
rem Get it here:
rem http://gnuwin32.sourceforge.net/packages/rpl.htm
rem Place rpl.exe from the bin folder inside the archive in the folder where
rem this batch file resides
if not exist rpl.exe goto no_rpl
echo Creating MSVC8 project files from the MSVC9 ones
copy /y msvc9\*.vcproj msvc8\
copy /y msvc9\*.sln msvc8\
copy /y msvc9\*.vsprops msvc8\
rpl -e -q "Version=\"9.00\"" "Version=\"8.00\"" msvc8\*.vcproj
rpl -e -q "Version=\"9,00\"" "Version=\"8,00\"" msvc8\*.vcproj
rpl -e -q "\tTargetFrameworkVersion=\"131072\"\n" "" msvc8\*.vcproj
rpl -e -q "Format Version 10.00" "Format Version 9.00" msvc8\residual.sln
rpl -e -q "Format Version 10,00" "Format Version 9,00" msvc8\residual.sln
goto the_end
:no_rpl
echo You need the Windows version of GNU rpl
echo Get it here:
echo http://gnuwin32.sourceforge.net/packages/rpl.htm
echo Place rpl.exe from the bin folder inside the archive in the folder where
echo this batch file resides
:the_end
pause

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Name=Residual
Exec=residual
Icon=residual.xpm
Icon=residual
Terminal=false
Type=Application
Categories=Game;AdventureGame;

View File

@ -1,6 +1,6 @@
#include "winresrc.h"
#if defined (__MINGW32__) || defined(__CYGWIN32__)
#if defined (__MINGW32__) || defined(__CYGWIN32__) || defined(HAS_INCLUDE_SET)
IDI_ICON ICON DISCARDABLE "icons/residual.ico"
#else
IDI_ICON ICON DISCARDABLE "../../icons/residual.ico"
@ -24,17 +24,13 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "\0"
VALUE "CompanyName", "Residual\0"
VALUE "FileDescription", "http://residual.sourceforge.net/\0"
VALUE "FileVersion", "0.0.6svn\0"
VALUE "InternalName", "residual\0"
VALUE "LegalCopyright", "Copyrights information are in AUTHORS file\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "residual.exe\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Residual\0"
VALUE "ProductVersion", "0.0.6svn\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"

View File

@ -1,6 +1,6 @@
#include "winresrc.h"
#if defined (__MINGW32__) || defined(__CYGWIN32__)
#if defined (__MINGW32__) || defined(__CYGWIN32__) || defined(HAS_INCLUDE_SET)
IDI_ICON ICON DISCARDABLE "icons/residual.ico"
#else
IDI_ICON ICON DISCARDABLE "../../icons/residual.ico"
@ -24,17 +24,13 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "\0"
VALUE "CompanyName", "Residual\0"
VALUE "FileDescription", "http://residual.sourceforge.net/\0"
VALUE "FileVersion", "@VERSION@\0"
VALUE "InternalName", "residual\0"
VALUE "LegalCopyright", "Copyrights information are in AUTHORS file\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "residual.exe\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Residual\0"
VALUE "ProductVersion", "@VERSION@\0"
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"

View File

@ -48,7 +48,7 @@
extern bool isSmartphone();
#endif
// FIXME: HACK for MidiEmu & error()
// FIXME: HACK for error()
Engine *g_engine = 0;
// Output formatter for debug() and error() which invokes
@ -260,7 +260,7 @@ void Engine::flipMute() {
if (ConfMan.hasKey("mute")) {
mute = !ConfMan.getBool("mute");
}
ConfMan.setBool("mute", mute);
syncSoundSettings();

View File

@ -122,7 +122,7 @@ static const GrimGameDescription gameDescriptions[] = {
"",
AD_ENTRY1s("local.m4b", "00c4eb73f6b6607ba3d4e8d3f956b37b", 3804862),
Common::EN_ANY,
Common::kPlatformPS2,
Common::kPlatformWindows,//Common::kPlatformPS2,
ADGF_NO_FLAGS,
GUIO_NONE
},

View File

@ -33,7 +33,7 @@
#include "sound/audiostream.h"
#include "sound/mixer.h"
#include "sound/raw.h"
#include "sound/decoders/raw.h"
namespace Grim {

View File

@ -30,7 +30,7 @@
#include "sound/audiostream.h"
#include "sound/mixer.h"
#include "sound/raw.h"
#include "sound/decoders/raw.h"
#include "engines/grim/smush/smush.h"

View File

@ -160,7 +160,7 @@ CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, in
#ifdef USE_RGB_COLOR
if (!format)
_format = Graphics::PixelFormat::createFormatCLUT8();
else
else
_format = *format;
_size = w * h * _format.bytesPerPixel;
_keycolor = keycolor & ((1 << (_format.bytesPerPixel << 3)) - 1);

View File

@ -29,9 +29,9 @@
#include "common/stack.h"
#include "common/singleton.h"
#include "graphics/pixelformat.h"
#ifdef USE_RGB_COLOR
#include "common/system.h"
#endif
//#ifdef USE_RGB_COLOR
//#include "common/system.h"
//#endif
namespace Graphics {
@ -70,7 +70,7 @@ public:
* @param keycolor the color value for the transparent color. This may not exceed
* the maximum color value as defined by format.
* @param targetScale the scale for which the cursor is designed
* @param format a pointer to the pixel format which the cursor graphic uses,
* @param format a pointer to the pixel format which the cursor graphic uses,
* CLUT8 will be used if this is NULL or not specified.
* @note It is ok for the buffer to be a NULL pointer. It is sometimes
* useful to push a "dummy" cursor and modify it later. The

View File

@ -25,7 +25,7 @@
#include "graphics/imagedec.h"
#include "common/file.h"
#include "common/system.h"
//#include "common/system.h"
namespace Graphics {
//

View File

@ -51,13 +51,13 @@ struct PixelFormat {
byte rShift, gShift, bShift, aShift; /**< Binary left shift of each color component in the pixel value. */
inline PixelFormat() {
bytesPerPixel =
rLoss = gLoss = bLoss = aLoss =
bytesPerPixel =
rLoss = gLoss = bLoss = aLoss =
rShift = gShift = bShift = aShift = 0;
}
inline PixelFormat(byte BytesPerPixel,
byte RBits, byte GBits, byte BBits, byte ABits,
inline PixelFormat(byte BytesPerPixel,
byte RBits, byte GBits, byte BBits, byte ABits,
byte RShift, byte GShift, byte BShift, byte AShift) {
bytesPerPixel = BytesPerPixel;
rLoss = 8 - RBits, gLoss = 8 - GBits, bLoss = 8 - BBits, aLoss = 8 - ABits;

View File

@ -286,7 +286,7 @@ bool ListWidget::handleKeyDown(Common::KeyState state) {
bool dirty = false;
int oldSelectedItem = _selectedItem;
if (!_editMode && state.keycode <= Common::KEYCODE_z && isprint((unsigned char)state.ascii)) {
if (!_editMode && isprint((unsigned char)state.ascii)) {
// Quick selection mode: Go to first list item starting with this key
// (or a substring accumulated from the last couple key presses).
// Only works in a useful fashion if the list entries are sorted.
@ -351,33 +351,27 @@ bool ListWidget::handleKeyDown(Common::KeyState state) {
}
break;
case Common::KEYCODE_UP:
case Common::KEYCODE_KP8:
if (_selectedItem > 0)
_selectedItem--;
break;
case Common::KEYCODE_DOWN:
case Common::KEYCODE_KP2:
if (_selectedItem < (int)_list.size() - 1)
_selectedItem++;
break;
case Common::KEYCODE_PAGEUP:
case Common::KEYCODE_KP9:
_selectedItem -= _entriesPerPage - 1;
if (_selectedItem < 0)
_selectedItem = 0;
break;
case Common::KEYCODE_PAGEDOWN:
case Common::KEYCODE_KP3:
_selectedItem += _entriesPerPage - 1;
if (_selectedItem >= (int)_list.size() )
_selectedItem = _list.size() - 1;
break;
case Common::KEYCODE_HOME:
case Common::KEYCODE_KP7:
_selectedItem = 0;
break;
case Common::KEYCODE_END:
case Common::KEYCODE_1:
_selectedItem = _list.size() - 1;
break;
default:
@ -642,7 +636,7 @@ void ListWidget::setFilter(const String &filter, bool redraw) {
} else {
// Restrict the list to everything which contains all words in _filter
// as substrings, ignoring case.
Common::StringTokenizer tok(_filter);
String tmp;
int n = 0;

View File

@ -228,19 +228,15 @@ void PopUpDialog::handleKeyDown(Common::KeyState state) {
close();
break;
case Common::KEYCODE_UP:
case Common::KEYCODE_KP8:
moveUp();
break;
case Common::KEYCODE_DOWN:
case Common::KEYCODE_KP2:
moveDown();
break;
case Common::KEYCODE_HOME:
case Common::KEYCODE_KP7:
setSelection(0);
break;
case Common::KEYCODE_END:
case Common::KEYCODE_KP1:
setSelection(_popUpBoss->_entries.size()-1);
break;
default:

View File

@ -58,7 +58,7 @@ enum {
static const char *copyright_text[] = {
"",
"C0""Copyright (C) 2003-2010 The Residual project",
"C0""Copyright (C) 2003-2011 The Residual project",
"C0""http://residual.sourceforge.net",
"",
"C0""Residual is the legal property of its developers, whose names are too numerous to list here. Please refer to the AUTHORS file distributed with this binary.",

View File

@ -341,8 +341,10 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
break;
}
case Common::KEYCODE_DELETE:
killChar();
drawLine(pos2line(_currentPos));
if (_currentPos < _promptEndPos) {
killChar();
drawLine(pos2line(_currentPos));
}
break;
case Common::KEYCODE_PAGEUP:
if (state.flags == Common::KBD_SHIFT) {
@ -386,21 +388,17 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
draw();
break;
case Common::KEYCODE_UP:
case Common::KEYCODE_KP8:
historyScroll(+1);
break;
case Common::KEYCODE_DOWN:
case Common::KEYCODE_KP2:
historyScroll(-1);
break;
case Common::KEYCODE_RIGHT:
case Common::KEYCODE_KP6:
if (_currentPos < _promptEndPos)
_currentPos++;
drawLine(pos2line(_currentPos));
break;
case Common::KEYCODE_LEFT:
case Common::KEYCODE_KP4:
if (_currentPos > _promptStartPos)
_currentPos--;
drawLine(pos2line(_currentPos));
@ -472,8 +470,10 @@ void ConsoleDialog::specialKeys(int keycode) {
void ConsoleDialog::killChar() {
for (int i = _currentPos; i < _promptEndPos; i++)
buffer(i) = buffer(i + 1);
buffer(_promptEndPos) = ' ';
_promptEndPos--;
if (_promptEndPos > _promptStartPos) {
buffer(_promptEndPos) = ' ';
_promptEndPos--;
}
}
void ConsoleDialog::killLine() {
@ -497,8 +497,10 @@ void ConsoleDialog::killLastWord() {
for (int i = _currentPos; i < _promptEndPos; i++)
buffer(i) = buffer(i + cnt);
buffer(_promptEndPos) = ' ';
_promptEndPos -= cnt;
if (_promptEndPos > _promptStartPos) {
buffer(_promptEndPos) = ' ';
_promptEndPos -= cnt;
}
}
void ConsoleDialog::addToHistory(const char *str) {

View File

@ -157,7 +157,7 @@ void Debugger::enter() {
g_readline_debugger = this;
rl_completion_entry_function = &readline_completionFunction;
char *line_read = 0;
do {
free(line_read);
@ -375,7 +375,7 @@ char *Debugger::readlineComplete(const char *input, int state) {
char *ret = (char *)malloc(iter->_key.size() + 1);
strcpy(ret, iter->_key.c_str());
return ret;
}
}
}
return 0;
}

View File

@ -124,7 +124,6 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
forcecaret = true;
break;
case Common::KEYCODE_LEFT:
case Common::KEYCODE_KP4:
if (_caretPos > 0) {
dirty = setCaretPos(_caretPos - 1);
}
@ -132,7 +131,6 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
dirty = true;
break;
case Common::KEYCODE_RIGHT:
case Common::KEYCODE_KP6:
if (_caretPos < (int)_editString.size()) {
dirty = setCaretPos(_caretPos + 1);
}
@ -140,12 +138,10 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
dirty = true;
break;
case Common::KEYCODE_HOME:
case Common::KEYCODE_KP7:
dirty = setCaretPos(0);
forcecaret = true;
break;
case Common::KEYCODE_END:
case Common::KEYCODE_KP1:
dirty = setCaretPos(_editString.size());
forcecaret = true;
break;

View File

@ -821,7 +821,7 @@ void LauncherDialog::editGame(int item) {
// default set nothing and use the global ScummVM settings. E.g. the user
// can set here an optional alternate music volume, or for specific games
// a different music driver etc.
// This is useful because e.g. MonkeyVGA needs Adlib music to have decent
// This is useful because e.g. MonkeyVGA needs AdLib music to have decent
// music support etc.
assert(item >= 0);
String gameId(ConfMan.get("gameid", _domains[item]));

View File

@ -732,6 +732,11 @@ void GlobalOptionsDialog::open() {
if (value == savePeriodValues[i])
_autosavePeriodPopUp->setSelected(i);
}
ThemeEngine::GraphicsMode mode = ThemeEngine::findMode(ConfMan.get("gui_renderer"));
if (mode == ThemeEngine::kGfxDisabled)
mode = ThemeEngine::_defaultRendererMode;
_rendererPopUp->setSelectedTag(mode);
}
void GlobalOptionsDialog::close() {
@ -761,6 +766,15 @@ void GlobalOptionsDialog::close() {
#endif
ConfMan.setInt("autosave_period", _autosavePeriodPopUp->getSelectedTag(), _domain);
GUI::ThemeEngine::GraphicsMode selected = (GUI::ThemeEngine::GraphicsMode)_rendererPopUp->getSelectedTag();
const char *cfg = GUI::ThemeEngine::findModeConfigName(selected);
if (!ConfMan.get("gui_renderer").equalsIgnoreCase(cfg)) {
// FIXME: Actually, any changes (including the theme change) should
// only become active *after* the options dialog has closed.
g_gui.loadNewTheme(g_gui.theme()->getThemeId(), selected);
ConfMan.set("gui_renderer", cfg, _domain);
}
}
OptionsDialog::close();
}

View File

@ -61,6 +61,7 @@ bundle: residual-static
iphonebundle: iphone
mkdir -p $(bundle_name)
cp $(srcdir)/dists/iphone/Info.plist $(bundle_name)/
cp $(DIST_FILES_DOCS) $(bundle_name)/
cp $(DIST_FILES_THEMES) $(bundle_name)/
#cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/
ldid -S residual

View File

@ -25,9 +25,9 @@
#include "sound/audiocd.h"
#include "sound/audiostream.h"
#include "sound/mp3.h"
#include "sound/vorbis.h"
#include "sound/flac.h"
#include "sound/decoders/mp3.h"
#include "sound/decoders/vorbis.h"
#include "sound/decoders/flac.h"
#include "engines/engine.h"
#include "common/util.h"
#include "common/system.h"

View File

@ -30,19 +30,19 @@
#include "common/util.h"
#include "sound/audiostream.h"
#include "sound/flac.h"
#include "sound/decoders/flac.h"
#include "sound/mixer.h"
#include "sound/mp3.h"
#include "sound/raw.h"
#include "sound/vorbis.h"
#include "sound/decoders/mp3.h"
#include "sound/decoders/raw.h"
#include "sound/decoders/vorbis.h"
namespace Audio {
struct StreamFileFormat {
/** Decodername */
const char* decoderName;
const char* fileExtension;
const char *decoderName;
const char *fileExtension;
/**
* Pointer to a function which tries to open a file of type StreamFormat.
* Return NULL in case of an error (invalid/nonexisting file).
@ -51,16 +51,16 @@ struct StreamFileFormat {
};
static const StreamFileFormat STREAM_FILEFORMATS[] = {
/* decoderName, fileExt, openStreamFuntion */
/* decoderName, fileExt, openStreamFuntion */
#ifdef USE_FLAC
{ "Flac", ".flac", makeFlacStream },
{ "Flac", ".fla", makeFlacStream },
{ "FLAC", ".flac", makeFLACStream },
{ "FLAC", ".fla", makeFLACStream },
#endif
#ifdef USE_VORBIS
{ "Ogg Vorbis", ".ogg", makeVorbisStream },
{ "Ogg Vorbis", ".ogg", makeVorbisStream },
#endif
#ifdef USE_MAD
{ "MPEG Layer 3", ".mp3", makeMP3Stream },
{ "MPEG Layer 3", ".mp3", makeMP3Stream },
#endif
{ NULL, NULL, NULL } // Terminator
@ -104,6 +104,9 @@ LoopingAudioStream::~LoopingAudioStream() {
}
int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
if ((_loops && _completeIterations == _loops) || !numSamples)
return 0;
int samplesRead = _parent->readBuffer(buffer, numSamples);
if (_parent->endOfStream()) {
@ -111,7 +114,7 @@ int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
if (_completeIterations == _loops)
return samplesRead;
int remainingSamples = numSamples - samplesRead;
const int remainingSamples = numSamples - samplesRead;
if (!_parent->rewind()) {
// TODO: Properly indicate error
@ -119,7 +122,7 @@ int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
return samplesRead;
}
samplesRead += _parent->readBuffer(buffer + samplesRead, remainingSamples);
return samplesRead + readBuffer(buffer + samplesRead, remainingSamples);
}
return samplesRead;
@ -164,8 +167,8 @@ SubLoopingAudioStream::SubLoopingAudioStream(SeekableAudioStream *stream,
DisposeAfterUse::Flag disposeAfterUse)
: _parent(stream), _disposeAfterUse(disposeAfterUse), _loops(loops),
_pos(0, getRate() * (isStereo() ? 2 : 1)),
_loopStart(loopStart.convertToFramerate(getRate() * (isStereo() ? 2 : 1))),
_loopEnd(loopEnd.convertToFramerate(getRate() * (isStereo() ? 2 : 1))),
_loopStart(convertTimeToStreamPos(loopStart, getRate(), isStereo())),
_loopEnd(convertTimeToStreamPos(loopEnd, getRate(), isStereo())),
_done(false) {
if (!_parent->rewind())
_done = true;
@ -212,9 +215,9 @@ int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
SubSeekableAudioStream::SubSeekableAudioStream(SeekableAudioStream *parent, const Timestamp start, const Timestamp end, DisposeAfterUse::Flag disposeAfterUse)
: _parent(parent), _disposeAfterUse(disposeAfterUse),
_start(start.convertToFramerate(getRate())),
_start(convertTimeToStreamPos(start, getRate(), isStereo())),
_pos(0, getRate() * (isStereo() ? 2 : 1)),
_length((end - start).convertToFramerate(getRate() * (isStereo() ? 2 : 1))) {
_length(convertTimeToStreamPos(end - start, getRate(), isStereo())) {
assert(_length.totalNumberOfFrames() % (isStereo() ? 2 : 1) == 0);
_parent->seek(_start);
@ -233,7 +236,7 @@ int SubSeekableAudioStream::readBuffer(int16 *buffer, const int numSamples) {
}
bool SubSeekableAudioStream::seek(const Timestamp &where) {
_pos = where.convertToFramerate(getRate());
_pos = convertTimeToStreamPos(where, getRate(), isStereo());
if (_pos > _length) {
_pos = _length;
return false;
@ -253,7 +256,7 @@ bool SubSeekableAudioStream::seek(const Timestamp &where) {
void QueuingAudioStream::queueBuffer(byte *data, uint32 size, DisposeAfterUse::Flag disposeAfterUse, byte flags) {
AudioStream *stream = makeRawMemoryStream(data, size, disposeAfterUse, getRate(), flags, 0, 0);
AudioStream *stream = makeRawStream(data, size, getRate(), flags, disposeAfterUse);
queueAudioStream(stream, DisposeAfterUse::YES);
}
@ -271,8 +274,8 @@ private:
AudioStream *_stream;
DisposeAfterUse::Flag _disposeAfterUse;
StreamHolder(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse)
: _stream(stream),
_disposeAfterUse(disposeAfterUse) {}
: _stream(stream),
_disposeAfterUse(disposeAfterUse) {}
};
/**
@ -303,7 +306,7 @@ private:
public:
QueuingAudioStreamImpl(int rate, bool stereo)
: _rate(rate), _stereo(stereo), _finished(false) {}
: _rate(rate), _stereo(stereo), _finished(false) {}
~QueuingAudioStreamImpl();
// Implement the AudioStream API
@ -360,12 +363,19 @@ int QueuingAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) {
return samplesDecoded;
}
QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo) {
return new QueuingAudioStreamImpl(rate, stereo);
}
Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo) {
Timestamp result(where.convertToFramerate(rate * (isStereo ? 2 : 1)));
// When the Stream is a stereo stream, we have to assure
// that the sample position is an even number.
if (isStereo && (result.totalNumberOfFrames() & 1))
return result.addFrames(-1); // We cut off one sample here.
else
return result;
}
} // End of namespace Audio

View File

@ -46,7 +46,7 @@ public:
/**
* Fill the given buffer with up to numSamples samples. Returns the actual
* number of samples read, or -1 if a critical error occured (note: you
* number of samples read, or -1 if a critical error occurred (note: you
* *must* check if this value is less than what you requested, this can
* happen when the stream is fully used up).
*
@ -86,7 +86,7 @@ public:
};
/**
* A rewindable audio stream. This allows for restting the AudioStream
* A rewindable audio stream. This allows for reseting the AudioStream
* to its initial state. Note that rewinding itself is not required to
* be working when the stream is being played by Mixer!
*/
@ -101,7 +101,7 @@ public:
};
/**
* A looping audio stream. This object does nothing beides using
* A looping audio stream. This object does nothing besides using
* a RewindableAudioStream to play a stream in a loop.
*/
class LoopingAudioStream : public AudioStream {
@ -113,7 +113,7 @@ public:
*
* @param stream Stream to loop
* @param loops How often to loop (0 = infinite)
* @param disposeAfteruse Destroy the stream after the LoopingAudioStream has finished playback.
* @param disposeAfterUse Destroy the stream after the LoopingAudioStream has finished playback.
*/
LoopingAudioStream(RewindableAudioStream *stream, uint loops, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
~LoopingAudioStream();
@ -124,7 +124,7 @@ public:
bool isStereo() const { return _parent->isStereo(); }
int getRate() const { return _parent->getRate(); }
/**
/**
* Returns number of loops the stream has played.
* @param numLoops number of loops to play, 0 - infinite
*/
@ -138,16 +138,16 @@ private:
};
/**
* Wrapper functionallity to efficiently create a stream, which might be looped.
* Wrapper functionality to efficiently create a stream, which might be looped.
*
* Note that this function does not return a LoopingAudioStream, because it does
* not create one, when the loop count is "1". This allows to keep the runtime
* overhead down, when the code does not require any functionallity only offered
* not create one when the loop count is "1". This allows to keep the runtime
* overhead down, when the code does not require any functionality only offered
* by LoopingAudioStream.
*
* @param stream Stream to loop (will be automatically destroyed, when the looping is done)
* @param loops How often to loop (0 = infinite)
* @return A new AudioStream, which offers the desired functionallity.
* @return A new AudioStream, which offers the desired functionality.
*/
AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops);
@ -161,10 +161,10 @@ public:
/**
* Tries to load a file by trying all available formats.
* In case of an error, the file handle will be closed, but deleting
* it is still the responsibilty of the caller.
* @param basename a filename without an extension
* @return an SeekableAudioStream ready to use in case of success;
* NULL in case of an error (e.g. invalid/nonexisting file)
* it is still the responsibility of the caller.
* @param basename a filename without an extension
* @return an SeekableAudioStream ready to use in case of success;
* NULL in case of an error (e.g. invalid/nonexisting file)
*/
static SeekableAudioStream *openStreamFile(const Common::String &basename);
@ -197,21 +197,21 @@ public:
};
/**
* Wrapper functionallity to efficiently create a stream, which might be looped
* Wrapper functionality to efficiently create a stream, which might be looped
* in a certain interval.
*
* This automatically starts the stream at time "start"!
*
* Note that this function does not return a LoopingAudioStream, because it does
* not create one, when the loop count is "1". This allows to keep the runtime
* overhead down, when the code does not require any functionallity only offered
* not create one when the loop count is "1". This allows to keep the runtime
* overhead down, when the code does not require any functionality only offered
* by LoopingAudioStream.
*
* @param stream Stream to loop (will be automatically destroyed, when the looping is done)
* @param start Starttime of the stream interval to be looped
* @param end End of the stream interval to be looped (a zero time, means till end)
* @param loops How often to loop (0 = infinite)
* @return A new AudioStream, which offers the desired functionallity.
* @return A new AudioStream, which offers the desired functionality.
*/
AudioStream *makeLoopingAudioStream(SeekableAudioStream *stream, Timestamp start, Timestamp end, uint loops);
@ -251,11 +251,12 @@ private:
bool _done;
};
/**
* A SubSeekableAudioStream provides access to a SeekableAudioStream
* just in the range [start, end).
* The same caveats apply to SubSeekableAudioStream as do to SeekableAudioStream.
*
*
* Manipulating the parent stream directly /will/ mess up a substream.
*
* IMPORTANT:
@ -312,8 +313,8 @@ public:
* Queue a block of raw audio data for playback. This stream
* will play all queued buffers, in the order they were
* queued. After all data contained in them has been played,
* the buffer will be delete[]'d (so make sure to allocate them
* with new[], not with malloc).
* the buffer will be released using free(). So make sure to
* allocate them with malloc(), not with new[]).
*/
void queueBuffer(byte *data, uint32 size, DisposeAfterUse::Flag disposeAfterUse, byte flags);
@ -336,16 +337,15 @@ public:
*/
QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo);
/**
* Calculates the sample, which the timestamp describes in a
* AudioStream with the given framerate.
* Converts a point in time to a precise sample offset
* with the given parameters.
*
* @param where point in time
* @param rate rate of the AudioStream
* @return sample index
* @param where Point in time.
* @param rate Rate of the stream.
* @param isStereo Is the stream a stereo stream?
*/
uint32 calculateSampleOffset(const Timestamp &where, int rate);
Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo);
} // End of namespace Audio

View File

@ -1,735 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#include "sound/flac.h"
#ifdef USE_FLAC
#include "common/debug.h"
#include "common/stream.h"
#include "common/util.h"
#include "sound/audiostream.h"
#include "sound/audiocd.h"
#define FLAC__NO_DLL // that MS-magic gave me headaches - just link the library you like
#include <FLAC/export.h>
// check if we have FLAC >= 1.1.3; LEGACY_FLAC code can be removed once FLAC-1.1.3 propagates everywhere
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
#define LEGACY_FLAC
#else
#undef LEGACY_FLAC
#endif
#ifdef LEGACY_FLAC
// Before FLAC 1.1.3, we needed to use the stream decoder API.
#include <FLAC/seekable_stream_decoder.h>
typedef uint FLAC_size_t;
#else
// With FLAC 1.1.3, the stream decoder API was merged into the regular
// stream API. In order to stay compatible with older FLAC versions, we
// simply add some typedefs and #ifdefs to map between the old and new API.
// We use the typedefs (instead of only #defines) in order to somewhat
// improve the readability of the code.
#include <FLAC/stream_decoder.h>
typedef size_t FLAC_size_t;
// Add aliases for the old names
typedef FLAC__StreamDecoderState FLAC__SeekableStreamDecoderState;
typedef FLAC__StreamDecoderReadStatus FLAC__SeekableStreamDecoderReadStatus;
typedef FLAC__StreamDecoderSeekStatus FLAC__SeekableStreamDecoderSeekStatus;
typedef FLAC__StreamDecoderTellStatus FLAC__SeekableStreamDecoderTellStatus;
typedef FLAC__StreamDecoderLengthStatus FLAC__SeekableStreamDecoderLengthStatus;
typedef FLAC__StreamDecoder FLAC__SeekableStreamDecoder;
#endif
namespace Audio {
#pragma mark -
#pragma mark --- Flac stream ---
#pragma mark -
static const uint MAX_OUTPUT_CHANNELS = 2;
class FlacInputStream : public SeekableAudioStream {
protected:
Common::SeekableReadStream *_inStream;
bool _disposeAfterUse;
::FLAC__SeekableStreamDecoder *_decoder;
/** Header of the stream */
FLAC__StreamMetadata_StreamInfo _streaminfo;
/** index + 1(!) of the last sample to be played */
FLAC__uint64 _lastSample;
/** total play time */
Timestamp _length;
/** true if the last sample was decoded from the FLAC-API - there might still be data in the buffer */
bool _lastSampleWritten;
typedef int16 SampleType;
enum { BUFTYPE_BITS = 16 };
enum {
// Maximal buffer size. According to the FLAC format specification, the block size is
// a 16 bit value (in fact it seems the maximal block size is 32768, but we play it safe).
BUFFER_SIZE = 65536
};
struct {
SampleType bufData[BUFFER_SIZE];
SampleType *bufReadPos;
uint bufFill;
} _sampleCache;
SampleType *_outBuffer;
uint _requestedSamples;
typedef void (*PFCONVERTBUFFERS)(SampleType*, const FLAC__int32*[], uint, const uint, const uint8);
PFCONVERTBUFFERS _methodConvertBuffers;
public:
FlacInputStream(Common::SeekableReadStream *inStream, bool dispose);
virtual ~FlacInputStream();
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return _streaminfo.channels >= 2; }
int getRate() const { return _streaminfo.sample_rate; }
bool endOfData() const {
// End of data is reached if there either is no valid stream data available,
// or if we reached the last sample and completely emptied the sample cache.
return _streaminfo.channels == 0 || (_lastSampleWritten && _sampleCache.bufFill == 0);
}
bool seek(const Timestamp &where);
Timestamp getLength() const { return _length; }
bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; }
protected:
uint getChannels() const { return MIN<uint>(_streaminfo.channels, MAX_OUTPUT_CHANNELS); }
bool allocateBuffer(uint minSamples);
inline FLAC__StreamDecoderState getStreamDecoderState() const;
inline bool processSingleBlock();
inline bool processUntilEndOfMetadata();
bool seekAbsolute(FLAC__uint64 sample);
inline ::FLAC__SeekableStreamDecoderReadStatus callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes);
inline ::FLAC__SeekableStreamDecoderSeekStatus callbackSeek(FLAC__uint64 absoluteByteOffset);
inline ::FLAC__SeekableStreamDecoderTellStatus callbackTell(FLAC__uint64 *absoluteByteOffset);
inline ::FLAC__SeekableStreamDecoderLengthStatus callbackLength(FLAC__uint64 *streamLength);
inline bool callbackEOF();
inline ::FLAC__StreamDecoderWriteStatus callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
inline void callbackMetadata(const ::FLAC__StreamMetadata *metadata);
inline void callbackError(::FLAC__StreamDecoderErrorStatus status);
private:
static ::FLAC__SeekableStreamDecoderReadStatus callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData);
static ::FLAC__SeekableStreamDecoderSeekStatus callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData);
static ::FLAC__SeekableStreamDecoderTellStatus callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData);
static ::FLAC__SeekableStreamDecoderLengthStatus callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData);
static FLAC__bool callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData);
static ::FLAC__StreamDecoderWriteStatus callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData);
static void callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData);
static void callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData);
void setBestConvertBufferMethod();
static void convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
static void convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
static void convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
static void convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
static void convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
};
FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool dispose)
#ifdef LEGACY_FLAC
: _decoder(::FLAC__seekable_stream_decoder_new()),
#else
: _decoder(::FLAC__stream_decoder_new()),
#endif
_inStream(inStream),
_disposeAfterUse(dispose),
_length(0, 1000), _lastSample(0),
_outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(false),
_methodConvertBuffers(&FlacInputStream::convertBuffersGeneric)
{
assert(_inStream);
memset(&_streaminfo, 0, sizeof(_streaminfo));
_sampleCache.bufReadPos = NULL;
_sampleCache.bufFill = 0;
_methodConvertBuffers = &FlacInputStream::convertBuffersGeneric;
bool success;
#ifdef LEGACY_FLAC
::FLAC__seekable_stream_decoder_set_read_callback(_decoder, &FlacInputStream::callWrapRead);
::FLAC__seekable_stream_decoder_set_seek_callback(_decoder, &FlacInputStream::callWrapSeek);
::FLAC__seekable_stream_decoder_set_tell_callback(_decoder, &FlacInputStream::callWrapTell);
::FLAC__seekable_stream_decoder_set_length_callback(_decoder, &FlacInputStream::callWrapLength);
::FLAC__seekable_stream_decoder_set_eof_callback(_decoder, &FlacInputStream::callWrapEOF);
::FLAC__seekable_stream_decoder_set_write_callback(_decoder, &FlacInputStream::callWrapWrite);
::FLAC__seekable_stream_decoder_set_metadata_callback(_decoder, &FlacInputStream::callWrapMetadata);
::FLAC__seekable_stream_decoder_set_error_callback(_decoder, &FlacInputStream::callWrapError);
::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void*)this);
success = (::FLAC__seekable_stream_decoder_init(_decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK);
#else
success = (::FLAC__stream_decoder_init_stream(
_decoder,
&FlacInputStream::callWrapRead,
&FlacInputStream::callWrapSeek,
&FlacInputStream::callWrapTell,
&FlacInputStream::callWrapLength,
&FlacInputStream::callWrapEOF,
&FlacInputStream::callWrapWrite,
&FlacInputStream::callWrapMetadata,
&FlacInputStream::callWrapError,
(void*)this
) == FLAC__STREAM_DECODER_INIT_STATUS_OK);
#endif
if (success) {
if (processUntilEndOfMetadata() && _streaminfo.channels > 0) {
_lastSample = _streaminfo.total_samples + 1;
_length = Timestamp(0, _lastSample - 1, getRate());
return; // no error occured
}
}
warning("FlacInputStream: could not create audio stream");
}
FlacInputStream::~FlacInputStream() {
if (_decoder != NULL) {
#ifdef LEGACY_FLAC
(void) ::FLAC__seekable_stream_decoder_finish(_decoder);
::FLAC__seekable_stream_decoder_delete(_decoder);
#else
(void) ::FLAC__stream_decoder_finish(_decoder);
::FLAC__stream_decoder_delete(_decoder);
#endif
}
if (_disposeAfterUse)
delete _inStream;
}
inline FLAC__StreamDecoderState FlacInputStream::getStreamDecoderState() const {
assert(_decoder != NULL);
#ifdef LEGACY_FLAC
return ::FLAC__seekable_stream_decoder_get_stream_decoder_state(_decoder);
#else
return ::FLAC__stream_decoder_get_state(_decoder);
#endif
}
inline bool FlacInputStream::processSingleBlock() {
assert(_decoder != NULL);
#ifdef LEGACY_FLAC
return 0 != ::FLAC__seekable_stream_decoder_process_single(_decoder);
#else
return 0 != ::FLAC__stream_decoder_process_single(_decoder);
#endif
}
inline bool FlacInputStream::processUntilEndOfMetadata() {
assert(_decoder != NULL);
#ifdef LEGACY_FLAC
return 0 != ::FLAC__seekable_stream_decoder_process_until_end_of_metadata(_decoder);
#else
return 0 != ::FLAC__stream_decoder_process_until_end_of_metadata(_decoder);
#endif
}
bool FlacInputStream::seekAbsolute(FLAC__uint64 sample) {
assert(_decoder != NULL);
#ifdef LEGACY_FLAC
const bool result = (0 != ::FLAC__seekable_stream_decoder_seek_absolute(_decoder, sample));
#else
const bool result = (0 != ::FLAC__stream_decoder_seek_absolute(_decoder, sample));
#endif
if (result) {
_lastSampleWritten = (_lastSample != 0 && sample >= _lastSample); // only set if we are SURE
}
return result;
}
bool FlacInputStream::seek(const Timestamp &where) {
_sampleCache.bufFill = 0;
_sampleCache.bufReadPos = NULL;
return seekAbsolute((FLAC__uint64)calculateSampleOffset(where, _streaminfo.sample_rate));
}
int FlacInputStream::readBuffer(int16 *buffer, const int numSamples) {
const uint numChannels = getChannels();
if (numChannels == 0) {
warning("FlacInputStream: Stream not sucessfully initialised, cant playback");
return -1; // streaminfo wasnt read!
}
assert(numSamples % numChannels == 0); // must be multiple of channels!
assert(buffer != NULL);
assert(_outBuffer == NULL);
assert(_requestedSamples == 0);
_outBuffer = buffer;
_requestedSamples = numSamples;
// If there is still data in our buffer from the last time around,
// copy that first.
if (_sampleCache.bufFill > 0) {
assert(_sampleCache.bufReadPos >= _sampleCache.bufData);
assert(_sampleCache.bufFill % numChannels == 0);
const uint copySamples = MIN((uint)numSamples, _sampleCache.bufFill);
memcpy(buffer, _sampleCache.bufReadPos, copySamples*sizeof(buffer[0]));
_outBuffer = buffer + copySamples;
_requestedSamples = numSamples - copySamples;
_sampleCache.bufReadPos += copySamples;
_sampleCache.bufFill -= copySamples;
}
bool decoderOk = true;
FLAC__StreamDecoderState state = getStreamDecoderState();
// Keep poking FLAC to process more samples until we completely satisfied the request
// respectively until we run out of data.
while (!_lastSampleWritten && _requestedSamples > 0 && state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) {
assert(_sampleCache.bufFill == 0);
assert(_requestedSamples % numChannels == 0);
processSingleBlock();
state = getStreamDecoderState();
if (state == FLAC__STREAM_DECODER_END_OF_STREAM)
_lastSampleWritten = true;
}
// Error handling
switch (state) {
case FLAC__STREAM_DECODER_END_OF_STREAM:
_lastSampleWritten = true;
break;
case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
break;
default:
decoderOk = false;
warning("FlacInputStream: An error occured while decoding. DecoderState is: %s",
FLAC__StreamDecoderStateString[getStreamDecoderState()]);
}
// Compute how many samples we actually produced
const int samples = (int)(_outBuffer - buffer);
assert(samples % numChannels == 0);
_outBuffer = NULL; // basically unnecessary, only for the purpose of the asserts
_requestedSamples = 0; // basically unnecessary, only for the purpose of the asserts
return decoderOk ? samples : -1;
}
inline ::FLAC__SeekableStreamDecoderReadStatus FlacInputStream::callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes) {
if (*bytes == 0) {
#ifdef LEGACY_FLAC
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */
#else
return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
#endif
}
const uint32 bytesRead = _inStream->read(buffer, *bytes);
if (bytesRead == 0) {
#ifdef LEGACY_FLAC
return _inStream->eos() ? FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
#else
return _inStream->eos() ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_ABORT;
#endif
}
*bytes = static_cast<uint>(bytesRead);
#ifdef LEGACY_FLAC
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
#else
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
#endif
}
void FlacInputStream::setBestConvertBufferMethod() {
PFCONVERTBUFFERS tempMethod = &FlacInputStream::convertBuffersGeneric;
const uint numChannels = getChannels();
const uint8 numBits = (uint8)_streaminfo.bits_per_sample;
assert(numChannels >= 1);
assert(numBits >= 4 && numBits <=32);
if (numChannels == 1) {
if (numBits == 8)
tempMethod = &FlacInputStream::convertBuffersMono8Bit;
if (numBits == BUFTYPE_BITS)
tempMethod = &FlacInputStream::convertBuffersMonoNS;
} else if (numChannels == 2) {
if (numBits == 8)
tempMethod = &FlacInputStream::convertBuffersStereo8Bit;
if (numBits == BUFTYPE_BITS)
tempMethod = &FlacInputStream::convertBuffersStereoNS;
} /* else ... */
_methodConvertBuffers = tempMethod;
}
// 1 channel, no scaling
void FlacInputStream::convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
assert(numChannels == 1);
assert(numBits == BUFTYPE_BITS);
FLAC__int32 const* inChannel1 = inChannels[0];
while (numSamples >= 4) {
bufDestination[0] = static_cast<SampleType>(inChannel1[0]);
bufDestination[1] = static_cast<SampleType>(inChannel1[1]);
bufDestination[2] = static_cast<SampleType>(inChannel1[2]);
bufDestination[3] = static_cast<SampleType>(inChannel1[3]);
bufDestination += 4;
inChannel1 += 4;
numSamples -= 4;
}
for (; numSamples > 0; --numSamples) {
*bufDestination++ = static_cast<SampleType>(*inChannel1++);
}
inChannels[0] = inChannel1;
assert(numSamples == 0); // dint copy too many samples
}
// 1 channel, scaling from 8Bit
void FlacInputStream::convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
assert(numChannels == 1);
assert(numBits == 8);
assert(8 < BUFTYPE_BITS);
FLAC__int32 const* inChannel1 = inChannels[0];
while (numSamples >= 4) {
bufDestination[0] = static_cast<SampleType>(inChannel1[0]) << (BUFTYPE_BITS - 8);
bufDestination[1] = static_cast<SampleType>(inChannel1[1]) << (BUFTYPE_BITS - 8);
bufDestination[2] = static_cast<SampleType>(inChannel1[2]) << (BUFTYPE_BITS - 8);
bufDestination[3] = static_cast<SampleType>(inChannel1[3]) << (BUFTYPE_BITS - 8);
bufDestination += 4;
inChannel1 += 4;
numSamples -= 4;
}
for (; numSamples > 0; --numSamples) {
*bufDestination++ = static_cast<SampleType>(*inChannel1++) << (BUFTYPE_BITS - 8);
}
inChannels[0] = inChannel1;
assert(numSamples == 0); // dint copy too many samples
}
// 2 channels, no scaling
void FlacInputStream::convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
assert(numChannels == 2);
assert(numBits == BUFTYPE_BITS);
assert(numSamples % 2 == 0); // must be integral multiply of channels
FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel
FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel
while (numSamples >= 2*2) {
bufDestination[0] = static_cast<SampleType>(inChannel1[0]);
bufDestination[1] = static_cast<SampleType>(inChannel2[0]);
bufDestination[2] = static_cast<SampleType>(inChannel1[1]);
bufDestination[3] = static_cast<SampleType>(inChannel2[1]);
bufDestination += 2 * 2;
inChannel1 += 2;
inChannel2 += 2;
numSamples -= 2 * 2;
}
while (numSamples > 0) {
bufDestination[0] = static_cast<SampleType>(*inChannel1++);
bufDestination[1] = static_cast<SampleType>(*inChannel2++);
bufDestination += 2;
numSamples -= 2;
}
inChannels[0] = inChannel1;
inChannels[1] = inChannel2;
assert(numSamples == 0); // dint copy too many samples
}
// 2 channels, scaling from 8Bit
void FlacInputStream::convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
assert(numChannels == 2);
assert(numBits == 8);
assert(numSamples % 2 == 0); // must be integral multiply of channels
assert(8 < BUFTYPE_BITS);
FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel
FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel
while (numSamples >= 2*2) {
bufDestination[0] = static_cast<SampleType>(inChannel1[0]) << (BUFTYPE_BITS - 8);
bufDestination[1] = static_cast<SampleType>(inChannel2[0]) << (BUFTYPE_BITS - 8);
bufDestination[2] = static_cast<SampleType>(inChannel1[1]) << (BUFTYPE_BITS - 8);
bufDestination[3] = static_cast<SampleType>(inChannel2[1]) << (BUFTYPE_BITS - 8);
bufDestination += 2 * 2;
inChannel1 += 2;
inChannel2 += 2;
numSamples -= 2 * 2;
}
while (numSamples > 0) {
bufDestination[0] = static_cast<SampleType>(*inChannel1++) << (BUFTYPE_BITS - 8);
bufDestination[1] = static_cast<SampleType>(*inChannel2++) << (BUFTYPE_BITS - 8);
bufDestination += 2;
numSamples -= 2;
}
inChannels[0] = inChannel1;
inChannels[1] = inChannel2;
assert(numSamples == 0); // dint copy too many samples
}
// all Purpose-conversion - slowest of em all
void FlacInputStream::convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
assert(numSamples % numChannels == 0); // must be integral multiply of channels
if (numBits < BUFTYPE_BITS) {
const uint8 kPower = (uint8)(BUFTYPE_BITS - numBits);
for (; numSamples > 0; numSamples -= numChannels) {
for (uint i = 0; i < numChannels; ++i)
*bufDestination++ = static_cast<SampleType>(*(inChannels[i]++)) << kPower;
}
} else if (numBits > BUFTYPE_BITS) {
const uint8 kPower = (uint8)(numBits - BUFTYPE_BITS);
for (; numSamples > 0; numSamples -= numChannels) {
for (uint i = 0; i < numChannels; ++i)
*bufDestination++ = static_cast<SampleType>(*(inChannels[i]++) >> kPower) ;
}
} else {
for (; numSamples > 0; numSamples -= numChannels) {
for (uint i = 0; i < numChannels; ++i)
*bufDestination++ = static_cast<SampleType>(*(inChannels[i]++));
}
}
assert(numSamples == 0); // dint copy too many samples
}
inline ::FLAC__StreamDecoderWriteStatus FlacInputStream::callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) {
assert(frame->header.channels == _streaminfo.channels);
assert(frame->header.sample_rate == _streaminfo.sample_rate);
assert(frame->header.bits_per_sample == _streaminfo.bits_per_sample);
assert(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER || _streaminfo.min_blocksize == _streaminfo.max_blocksize);
// We require that either the sample cache is empty, or that no samples were requested
assert(_sampleCache.bufFill == 0 || _requestedSamples == 0);
uint numSamples = frame->header.blocksize;
const uint numChannels = getChannels();
const uint8 numBits = (uint8)_streaminfo.bits_per_sample;
assert(_requestedSamples % numChannels == 0); // must be integral multiply of channels
const FLAC__uint64 firstSampleNumber = (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) ?
frame->header.number.sample_number : (static_cast<FLAC__uint64>(frame->header.number.frame_number)) * _streaminfo.max_blocksize;
// Check whether we are about to reach beyond the last sample we are supposed to play.
if (_lastSample != 0 && firstSampleNumber + numSamples >= _lastSample) {
numSamples = (uint)(firstSampleNumber >= _lastSample ? 0 : _lastSample - firstSampleNumber);
_lastSampleWritten = true;
}
// The value in _requestedSamples counts raw samples, so if there are more than one
// channel, we have to multiply the number of available sample "pairs" by numChannels
numSamples *= numChannels;
const FLAC__int32 *inChannels[MAX_OUTPUT_CHANNELS];
for (uint i = 0; i < numChannels; ++i)
inChannels[i] = buffer[i];
// write the incoming samples directly into the buffer provided to us by the mixer
if (_requestedSamples > 0) {
assert(_requestedSamples % numChannels == 0);
assert(_outBuffer != NULL);
// Copy & convert the available samples (limited both by how many we have available, and
// by how many are actually needed).
const uint copySamples = MIN(_requestedSamples, numSamples);
(*_methodConvertBuffers)(_outBuffer, inChannels, copySamples, numChannels, numBits);
_requestedSamples -= copySamples;
numSamples -= copySamples;
_outBuffer += copySamples;
}
// Write all remaining samples (i.e. those which didn't fit into the mixer buffer)
// into the sample cache.
if (_sampleCache.bufFill == 0)
_sampleCache.bufReadPos = _sampleCache.bufData;
const uint cacheSpace = (_sampleCache.bufData + BUFFER_SIZE) - (_sampleCache.bufReadPos + _sampleCache.bufFill);
assert(numSamples <= cacheSpace);
(*_methodConvertBuffers)(_sampleCache.bufReadPos + _sampleCache.bufFill, inChannels, numSamples, numChannels, numBits);
_sampleCache.bufFill += numSamples;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
inline ::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callbackSeek(FLAC__uint64 absoluteByteOffset) {
_inStream->seek(absoluteByteOffset, SEEK_SET);
const bool result = (absoluteByteOffset == (FLAC__uint64)_inStream->pos());
#ifdef LEGACY_FLAC
return result ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
#else
return result ? FLAC__STREAM_DECODER_SEEK_STATUS_OK : FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
#endif
}
inline ::FLAC__SeekableStreamDecoderTellStatus FlacInputStream::callbackTell(FLAC__uint64 *absoluteByteOffset) {
*absoluteByteOffset = static_cast<FLAC__uint64>(_inStream->pos());
#ifdef LEGACY_FLAC
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
#else
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
#endif
}
inline ::FLAC__SeekableStreamDecoderLengthStatus FlacInputStream::callbackLength(FLAC__uint64 *streamLength) {
*streamLength = static_cast<FLAC__uint64>(_inStream->size());
#ifdef LEGACY_FLAC
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
#else
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
#endif
}
inline bool FlacInputStream::callbackEOF() {
return _inStream->eos();
}
inline void FlacInputStream::callbackMetadata(const ::FLAC__StreamMetadata *metadata) {
assert(_decoder != NULL);
assert(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); // others arent really interesting
_streaminfo = metadata->data.stream_info;
setBestConvertBufferMethod(); // should be set after getting stream-information. FLAC always parses the info first
}
inline void FlacInputStream::callbackError(::FLAC__StreamDecoderErrorStatus status) {
// some of these are non-critical-Errors
debug(1, "FlacInputStream: An error occured while decoding. DecoderState is: %s",
FLAC__StreamDecoderErrorStatusString[status]);
}
/* Static Callback Wrappers */
::FLAC__SeekableStreamDecoderReadStatus FlacInputStream::callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
return instance->callbackRead(buffer, bytes);
}
::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
return instance->callbackSeek(absoluteByteOffset);
}
::FLAC__SeekableStreamDecoderTellStatus FlacInputStream::callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
return instance->callbackTell(absoluteByteOffset);
}
::FLAC__SeekableStreamDecoderLengthStatus FlacInputStream::callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
return instance->callbackLength(streamLength);
}
FLAC__bool FlacInputStream::callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
return instance->callbackEOF();
}
::FLAC__StreamDecoderWriteStatus FlacInputStream::callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
return instance->callbackWrite(frame, buffer);
}
void FlacInputStream::callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
instance->callbackMetadata(metadata);
}
void FlacInputStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData) {
FlacInputStream *instance = (FlacInputStream *)clientData;
assert(0 != instance);
instance->callbackError(status);
}
#pragma mark -
#pragma mark --- Flac factory functions ---
#pragma mark -
SeekableAudioStream *makeFlacStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse) {
return new FlacInputStream(stream, disposeAfterUse);
}
} // End of namespace Audio
#endif // #ifdef USE_FLAC

View File

@ -1,73 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
/**
* @file
* Sound decoder used in engines:
* - agos
* - kyra
* - m4
* - queen
* - saga
* - scumm
* - sword1
* - sword2
* - touche
* - tucker
*/
#ifndef SOUND_FLAC_H
#define SOUND_FLAC_H
#include "common/types.h"
#include "common/sys.h"
#ifdef USE_FLAC
namespace Common {
class SeekableReadStream;
}
namespace Audio {
class AudioStream;
class SeekableAudioStream;
/**
* Create a new SeekableAudioStream from the FLAC data in the given stream.
* Allows for seeking (which is why we require a SeekableReadStream).
*
* @param stream the SeekableReadStream from which to read the FLAC data
* @param disposeAfterUse whether to delete the stream after use
* @return a new SeekableAudioStream, or NULL, if an error occured
*/
SeekableAudioStream *makeFlacStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse);
} // End of namespace Audio
#endif // #ifdef USE_FLAC
#endif // #ifndef SOUND_FLAC_H

View File

@ -43,7 +43,7 @@ const Config::EmulatorDescription Config::_drivers[] = {
{ "auto", "<default>", kAuto, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
{ "mame", "MAME OPL emulator", kMame, kFlagOpl2 },
#ifndef DISABLE_DOSBOX_OPL
{ "db", "DOSBox OPL emulator (experimental)", kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
{ "db", "DOSBox OPL emulator", kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
#endif
{ 0, 0, 0, 0 }
};
@ -90,6 +90,8 @@ Config::DriverId Config::detect(OplType type) {
}
// Detect the first matching emulator
drv = -1;
for (int i = 1; _drivers[i].name; ++i) {
if (_drivers[i].flags & flags) {
drv = _drivers[i].id;
@ -100,6 +102,10 @@ Config::DriverId Config::detect(OplType type) {
return drv;
}
OPL *Config::create(OplType type) {
return create(kAuto, type);
}
OPL *Config::create(DriverId driver, OplType type) {
// On invalid driver selection, we try to do some fallback detection
if (driver == -1) {

View File

@ -85,7 +85,7 @@ public:
* Wrapper to easily init an OPL chip, without specifing an emulator.
* By default it will try to initialize an OPL2 emulator, thus an AdLib card.
*/
static OPL *create(OplType type = kOpl2) { return create(detect(type), type); }
static OPL *create(OplType type = kOpl2);
private:
static const EmulatorDescription _drivers[];

View File

@ -83,7 +83,7 @@ static const MidiDriverDescription s_musicDrivers[] = {
{"mt32", "MT-32 Emulation", MD_MT32, MDT_MIDI},
#endif
// The flags for the "adlib" driver indicates that it can do adlib and MIDI.
// The flags for the "adlib" driver indicates that it can do AdLib and MIDI.
{"adlib", "AdLib", MD_ADLIB, MDT_ADLIB},
{"pcspk", "PC Speaker", MD_PCSPK, MDT_PCSPK},
{"pcjr", "IBM PCjr", MD_PCJR, MDT_PCSPK},

View File

@ -100,7 +100,7 @@ enum MidiDriverFlags {
MDT_NONE = 0,
MDT_PCSPK = 1 << 0, // PC Speaker: Maps to MD_PCSPK and MD_PCJR
MDT_CMS = 1 << 1, // Creative Music System / Gameblaster: Maps to MD_CMS
MDT_ADLIB = 1 << 2, // Adlib: Maps to MD_ADLIB
MDT_ADLIB = 1 << 2, // AdLib: Maps to MD_ADLIB
MDT_TOWNS = 1 << 3, // FM-TOWNS: Maps to MD_TOWNS
MDT_MIDI = 1 << 4, // Real MIDI
MDT_PREFER_MIDI = 1 << 5 // Real MIDI output is preferred

View File

@ -86,7 +86,7 @@ public:
* Is the mixer ready and setup? This may not be the case on systems which
* don't support digital sound output. In that case, the mixer proc may
* never be called. That in turn can cause breakage in games which try to
* sync with an audio stream. In particular, the Adlib MIDI emulation...
* sync with an audio stream. In particular, the AdLib MIDI emulation...
*
* @return whether the mixer is ready and setup
*

View File

@ -3,18 +3,18 @@ MODULE := sound
MODULE_OBJS := \
audiocd.o \
audiostream.o \
flac.o \
fmopl.o \
mididrv.o \
midiparser.o \
mixer.o \
mp3.o \
mpu401.o \
musicplugin.o \
null.o \
raw.o \
timestamp.o \
vorbis.o \
decoders/flac.o \
decoders/mp3.o \
decoders/raw.o \
decoders/vorbis.o \
softsynth/adlib.o \
softsynth/opl/dosbox.o \
softsynth/opl/mame.o \

View File

@ -1,349 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#include "sound/mp3.h"
#ifdef USE_MAD
#include "common/debug.h"
#include "common/stream.h"
#include "common/util.h"
#include "sound/audiocd.h"
#include "sound/audiostream.h"
#include <mad.h>
namespace Audio {
#pragma mark -
#pragma mark --- MP3 (MAD) stream ---
#pragma mark -
class MP3InputStream : public SeekableAudioStream {
protected:
enum State {
MP3_STATE_INIT, // Need to init the decoder
MP3_STATE_READY, // ready for processing data
MP3_STATE_EOS // end of data reached (may need to loop)
};
Common::SeekableReadStream *_inStream;
DisposeAfterUse::Flag _disposeAfterUse;
uint _posInFrame;
State _state;
Timestamp _length;
mad_timer_t _totalTime;
mad_stream _stream;
mad_frame _frame;
mad_synth _synth;
enum {
BUFFER_SIZE = 5 * 8192
};
// This buffer contains a slab of input data
byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
public:
MP3InputStream(Common::SeekableReadStream *inStream,
DisposeAfterUse::Flag dispose);
~MP3InputStream();
int readBuffer(int16 *buffer, const int numSamples);
bool endOfData() const { return _state == MP3_STATE_EOS; }
bool isStereo() const { return MAD_NCHANNELS(&_frame.header) == 2; }
int getRate() const { return _frame.header.samplerate; }
bool seek(const Timestamp &where);
Timestamp getLength() const { return _length; }
protected:
void decodeMP3Data();
void readMP3Data();
void initStream();
void readHeader();
void deinitStream();
};
MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
_inStream(inStream),
_disposeAfterUse(dispose),
_posInFrame(0),
_state(MP3_STATE_INIT),
_length(0, 1000),
_totalTime(mad_timer_zero) {
// The MAD_BUFFER_GUARD must always contain zeros (the reason
// for this is that the Layer III Huffman decoder of libMAD
// may read a few bytes beyond the end of the input buffer).
memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD);
// Calculate the length of the stream
initStream();
while (_state != MP3_STATE_EOS)
readHeader();
_length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate());
deinitStream();
// Reinit stream
_state = MP3_STATE_INIT;
// Decode the first chunk of data. This is necessary so that _frame
// is setup and isStereo() and getRate() return correct results.
decodeMP3Data();
}
MP3InputStream::~MP3InputStream() {
deinitStream();
if (_disposeAfterUse == DisposeAfterUse::YES)
delete _inStream;
}
void MP3InputStream::decodeMP3Data() {
do {
if (_state == MP3_STATE_INIT)
initStream();
if (_state == MP3_STATE_EOS)
return;
// If necessary, load more data into the stream decoder
if (_stream.error == MAD_ERROR_BUFLEN)
readMP3Data();
while (_state == MP3_STATE_READY) {
// TODO: Do we need to use readHeader, when we do not do any seeking here?
readHeader();
// Decode the next frame
if (mad_frame_decode(&_frame, &_stream) == -1) {
if (_stream.error == MAD_ERROR_BUFLEN) {
break; // Read more data
} else if (MAD_RECOVERABLE(_stream.error)) {
// Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here.
// These are normal and expected (caused by our frame skipping (i.e. "seeking")
// code above).
debug(6, "MP3InputStream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
continue;
} else {
warning("MP3InputStream: Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
break;
}
}
// Synthesize PCM data
mad_synth_frame(&_synth, &_frame);
_posInFrame = 0;
break;
}
} while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);
if (_stream.error != MAD_ERROR_NONE)
_state = MP3_STATE_EOS;
}
void MP3InputStream::readMP3Data() {
uint32 remaining = 0;
// Give up immediately if we already used up all data in the stream
if (_inStream->eos()) {
_state = MP3_STATE_EOS;
return;
}
if (_stream.next_frame) {
// If there is still data in the MAD stream, we need to preserve it.
// Note that we use memmove, as we are reusing the same buffer,
// and hence the data regions we copy from and to may overlap.
remaining = _stream.bufend - _stream.next_frame;
assert(remaining < BUFFER_SIZE); // Paranoia check
memmove(_buf, _stream.next_frame, remaining);
}
// Try to read the next block
uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining);
if (size <= 0) {
_state = MP3_STATE_EOS;
return;
}
// Feed the data we just read into the stream decoder
_stream.error = MAD_ERROR_NONE;
mad_stream_buffer(&_stream, _buf, size + remaining);
}
bool MP3InputStream::seek(const Timestamp &where) {
if (where == _length) {
_state = MP3_STATE_EOS;
return true;
} else if (where > _length) {
return false;
}
const uint32 time = where.msecs();
mad_timer_t destination;
mad_timer_set(&destination, time / 1000, time % 1000, 1000);
if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0)
initStream();
while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
readHeader();
return (_state != MP3_STATE_EOS);
}
void MP3InputStream::initStream() {
if (_state != MP3_STATE_INIT)
deinitStream();
// Init MAD
mad_stream_init(&_stream);
mad_frame_init(&_frame);
mad_synth_init(&_synth);
// Reset the stream data
_inStream->seek(0, SEEK_SET);
_totalTime = mad_timer_zero;
_posInFrame = 0;
// Update state
_state = MP3_STATE_READY;
// Read the first few sample bytes
readMP3Data();
}
void MP3InputStream::readHeader() {
if (_state != MP3_STATE_READY)
return;
// If necessary, load more data into the stream decoder
if (_stream.error == MAD_ERROR_BUFLEN)
readMP3Data();
while (_state != MP3_STATE_EOS) {
_stream.error = MAD_ERROR_NONE;
// Decode the next header. Note: mad_frame_decode would do this for us, too.
// However, for seeking we don't want to decode the full frame (else it would
// be far too slow). Hence we perform this explicitly in a separate step.
if (mad_header_decode(&_frame.header, &_stream) == -1) {
if (_stream.error == MAD_ERROR_BUFLEN) {
readMP3Data(); // Read more data
continue;
} else if (MAD_RECOVERABLE(_stream.error)) {
debug(6, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
continue;
} else {
warning("MP3InputStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
break;
}
}
// Sum up the total playback time so far
mad_timer_add(&_totalTime, _frame.header.duration);
break;
}
if (_stream.error != MAD_ERROR_NONE)
_state = MP3_STATE_EOS;
}
void MP3InputStream::deinitStream() {
if (_state == MP3_STATE_INIT)
return;
// Deinit MAD
mad_synth_finish(&_synth);
mad_frame_finish(&_frame);
mad_stream_finish(&_stream);
_state = MP3_STATE_EOS;
}
static inline int scale_sample(mad_fixed_t sample) {
// round
sample += (1L << (MAD_F_FRACBITS - 16));
// clip
if (sample > MAD_F_ONE - 1)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
// quantize and scale to not saturate when mixing a lot of channels
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
int MP3InputStream::readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
// Keep going as long as we have input available
while (samples < numSamples && _state != MP3_STATE_EOS) {
const int len = MIN(numSamples, samples + (int)(_synth.pcm.length - _posInFrame) * MAD_NCHANNELS(&_frame.header));
while (samples < len) {
*buffer++ = (int16)scale_sample(_synth.pcm.samples[0][_posInFrame]);
samples++;
if (MAD_NCHANNELS(&_frame.header) == 2) {
*buffer++ = (int16)scale_sample(_synth.pcm.samples[1][_posInFrame]);
samples++;
}
_posInFrame++;
}
if (_posInFrame >= _synth.pcm.length) {
// We used up all PCM data in the current frame -- read & decode more
decodeMP3Data();
}
}
return samples;
}
#pragma mark -
#pragma mark --- MP3 factory functions ---
#pragma mark -
SeekableAudioStream *makeMP3Stream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse) {
return new MP3InputStream(stream, disposeAfterUse);
}
} // End of namespace Audio
#endif // #ifdef USE_MAD

View File

@ -1,73 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
/**
* @file
* Sound decoder used in engines:
* - agos
* - kyra
* - m4
* - queen
* - saga
* - scumm
* - sword1
* - sword2
* - touche
* - tucker
*/
#ifndef SOUND_MP3_H
#define SOUND_MP3_H
#include "common/types.h"
#include "common/sys.h"
#ifdef USE_MAD
namespace Common {
class SeekableReadStream;
}
namespace Audio {
class AudioStream;
class SeekableAudioStream;
/**
* Create a new SeekableAudioStream from the MP3 data in the given stream.
* Allows for seeking (which is why we require a SeekableReadStream).
*
* @param stream the SeekableReadStream from which to read the MP3 data
* @param disposeAfterUse whether to delete the stream after use
* @return a new SeekableAudioStream, or NULL, if an error occured
*/
SeekableAudioStream *makeMP3Stream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse);
} // End of namespace Audio
#endif // #ifdef USE_MAD
#endif // #ifndef SOUND_MP3_H

View File

@ -331,7 +331,7 @@ public:
template<bool stereo, bool reverseStereo>
RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) {
if (outrate && inrate != outrate) {
if (inrate != outrate) {
if ((inrate % outrate) == 0) {
return new SimpleRateConverter<stereo, reverseStereo>(inrate, outrate);
} else {

View File

@ -1,466 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#include "common/endian.h"
#include "common/stream.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
#include "sound/raw.h"
namespace Audio {
// This used to be an inline template function, but
// buggy template function handling in MSVC6 forced
// us to go with the macro approach. So far this is
// the only template function that MSVC6 seemed to
// compile incorrectly. Knock on wood.
#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
// TODO: Get rid of this
uint32 calculateSampleOffset(const Timestamp &where, int rate) {
return where.convertToFramerate(rate).totalNumberOfFrames();
}
#pragma mark -
#pragma mark --- RawMemoryStream ---
#pragma mark -
/**
* A simple raw audio stream, purely memory based. It operates on a single
* block of data, which is passed to it upon creation.
* Optionally supports looping the sound.
*
* Design note: This code tries to be as efficient as possible (without
* resorting to assembly, that is). To this end, it is written as a template
* class. This way the compiler can create optimized code for each special
* case. This results in a total of 12 versions of the code being generated.
*/
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
class RawMemoryStream : public SeekableAudioStream {
protected:
const byte *_ptr;
const byte *_end;
const int _rate;
const byte *_origPtr;
const DisposeAfterUse::Flag _disposeAfterUse;
const Timestamp _playtime;
public:
RawMemoryStream(int rate, const byte *ptr, uint len, DisposeAfterUse::Flag autoFreeMemory)
: _ptr(ptr), _end(ptr+len), _rate(rate), _origPtr(ptr),
_disposeAfterUse(autoFreeMemory),
_playtime(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate) {
}
virtual ~RawMemoryStream() {
if (_disposeAfterUse == DisposeAfterUse::YES)
delete[] const_cast<byte *>(_origPtr);
}
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return stereo; }
bool endOfData() const { return _ptr >= _end; }
int getRate() const { return _rate; }
bool seek(const Timestamp &where);
Timestamp getLength() const { return _playtime; }
};
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
int RawMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
int samples = numSamples;
while (samples > 0 && _ptr < _end) {
int len = MIN(samples, (int)(_end - _ptr) / (is16Bit ? 2 : 1));
samples -= len;
do {
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
_ptr += (is16Bit ? 2 : 1);
} while (--len);
}
return numSamples-samples;
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
bool RawMemoryStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
const uint8 *ptr = _origPtr + calculateSampleOffset(where, getRate()) * (is16Bit ? 2 : 1) * (stereo ? 2 : 1);
if (ptr > _end) {
_ptr = _end;
return false;
} else if (ptr == _end) {
_ptr = _end;
return true;
} else {
_ptr = ptr;
return true;
}
}
#pragma mark -
#pragma mark --- RawDiskStream ---
#pragma mark -
/**
* RawDiskStream. This can stream raw PCM audio data from disk. The
* function takes an pointer to an array of RawDiskStreamAudioBlock which defines the
* start position and length of each block of uncompressed audio in the stream.
*/
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
class RawDiskStream : public SeekableAudioStream {
// Allow backends to override buffer size
#ifdef CUSTOM_AUDIO_BUFFER_SIZE
static const int32 BUFFER_SIZE = CUSTOM_AUDIO_BUFFER_SIZE;
#else
static const int32 BUFFER_SIZE = 16384;
#endif
protected:
byte* _buffer; ///< Streaming buffer
const byte *_ptr; ///< Pointer to current position in stream buffer
const int _rate; ///< Sample rate of stream
Timestamp _playtime; ///< Calculated total play time
Common::SeekableReadStream *_stream; ///< Stream to read data from
int32 _filePos; ///< Current position in stream
int32 _diskLeft; ///< Samples left in stream in current block not yet read to buffer
int32 _bufferLeft; ///< Samples left in buffer in current block
const DisposeAfterUse::Flag _disposeAfterUse; ///< Indicates whether the stream object should be deleted when this RawDiskStream is destructed
RawDiskStreamAudioBlock *_audioBlock; ///< Audio block list
const int _audioBlockCount; ///< Number of blocks in _audioBlock
int _currentBlock; ///< Current audio block number
public:
RawDiskStream(int rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block, uint numBlocks)
: _rate(rate), _playtime(0, rate), _stream(stream), _disposeAfterUse(disposeStream),
_audioBlockCount(numBlocks) {
assert(numBlocks > 0);
// Allocate streaming buffer
if (is16Bit) {
_buffer = (byte *)malloc(BUFFER_SIZE * sizeof(int16));
} else {
_buffer = (byte *)malloc(BUFFER_SIZE * sizeof(byte));
}
_ptr = _buffer;
_bufferLeft = 0;
// Copy audio block data to our buffer
// TODO: Replace this with a Common::Array or Common::List to
// make it a little friendlier.
_audioBlock = new RawDiskStreamAudioBlock[numBlocks];
memcpy(_audioBlock, block, numBlocks * sizeof(RawDiskStreamAudioBlock));
// Set current buffer state, playing first block
_currentBlock = 0;
_filePos = _audioBlock[_currentBlock].pos;
_diskLeft = _audioBlock[_currentBlock].len;
// Add up length of all blocks in order to caluclate total play time
int len = 0;
for (int r = 0; r < _audioBlockCount; r++) {
len += _audioBlock[r].len;
}
_playtime = Timestamp(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate);
}
virtual ~RawDiskStream() {
if (_disposeAfterUse == DisposeAfterUse::YES) {
delete _stream;
}
delete[] _audioBlock;
free(_buffer);
}
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return stereo; }
bool endOfData() const { return (_currentBlock == _audioBlockCount - 1) && (_diskLeft == 0) && (_bufferLeft == 0); }
int getRate() const { return _rate; }
Timestamp getLength() const { return _playtime; }
bool seek(const Timestamp &where);
};
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
int RawDiskStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
int oldPos = _stream->pos();
bool restoreFilePosition = false;
int samples = numSamples;
while (samples > 0 && ((_diskLeft > 0 || _bufferLeft > 0) || (_currentBlock != _audioBlockCount - 1)) ) {
// Output samples in the buffer to the output
int len = MIN<int>(samples, _bufferLeft);
samples -= len;
_bufferLeft -= len;
while (len > 0) {
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
_ptr += (is16Bit ? 2 : 1);
len--;
}
// Have we now finished this block? If so, read the next block
if ((_bufferLeft == 0) && (_diskLeft == 0) && (_currentBlock != _audioBlockCount - 1)) {
// Next block
_currentBlock++;
_filePos = _audioBlock[_currentBlock].pos;
_diskLeft = _audioBlock[_currentBlock].len;
}
// Now read more data from disk if there is more to be read
if ((_bufferLeft == 0) && (_diskLeft > 0)) {
int32 readAmount = MIN(_diskLeft, BUFFER_SIZE);
_stream->seek(_filePos, SEEK_SET);
_stream->read(_buffer, readAmount * (is16Bit? 2: 1));
// Amount of data in buffer is now the amount read in, and
// the amount left to read on disk is decreased by the same amount
_bufferLeft = readAmount;
_diskLeft -= readAmount;
_ptr = (byte *)_buffer;
_filePos += readAmount * (is16Bit ? 2 : 1);
// Set this flag now we've used the file, it restores it's
// original position.
restoreFilePosition = true;
}
}
// In case calling code relies on the position of this stream staying
// constant, I restore the location if I've changed it. This is probably
// not necessary.
if (restoreFilePosition) {
_stream->seek(oldPos, SEEK_SET);
}
return numSamples - samples;
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
bool RawDiskStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
const uint32 seekSample = calculateSampleOffset(where, getRate()) * (stereo ? 2 : 1);
uint32 curSample = 0;
// Search for the disk block in which the specific sample is placed
_currentBlock = 0;
while (_currentBlock < _audioBlockCount) {
uint32 nextBlockSample = curSample + _audioBlock[_currentBlock].len;
if (nextBlockSample > seekSample)
break;
curSample = nextBlockSample;
++_currentBlock;
}
_filePos = 0;
_diskLeft = 0;
_bufferLeft = 0;
if (_currentBlock == _audioBlockCount) {
return ((seekSample - curSample) == (uint32)_audioBlock[_currentBlock - 1].len);
} else {
const uint32 offset = seekSample - curSample;
_filePos = _audioBlock[_currentBlock].pos + offset * (is16Bit ? 2 : 1);
_diskLeft = _audioBlock[_currentBlock].len - offset;
return true;
}
}
#pragma mark -
#pragma mark --- Raw stream factories ---
#pragma mark -
/* In the following, we use preprocessor / macro tricks to simplify the code
* which instantiates the input streams. We used to use template functions for
* this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
* comes to this feature of C++... so as a compromise we use macros to cut down
* on the (source) code duplication a bit.
* So while normally macro tricks are said to make maintenance harder, in this
* particular case it should actually help it :-)
*/
#define MAKE_LINEAR(STEREO, UNSIGNED) \
if (is16Bit) { \
if (isLE) \
return new RawMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, autoFree); \
else \
return new RawMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, autoFree); \
} else \
return new RawMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, autoFree)
SeekableAudioStream *makeRawMemoryStream(const byte *ptr, uint32 len,
DisposeAfterUse::Flag autoFree,
int rate, byte flags) {
const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
const bool isUnsigned = (flags & Audio::FLAG_UNSIGNED) != 0;
const bool isLE = (flags & Audio::FLAG_LITTLE_ENDIAN) != 0;
// Verify the buffer sizes are sane
if (is16Bit && isStereo) {
assert((len & 3) == 0);
} else if (is16Bit || isStereo) {
assert((len & 1) == 0);
}
if (isStereo) {
if (isUnsigned) {
MAKE_LINEAR(true, true);
} else {
MAKE_LINEAR(true, false);
}
} else {
if (isUnsigned) {
MAKE_LINEAR(false, true);
} else {
MAKE_LINEAR(false, false);
}
}
}
AudioStream *makeRawMemoryStream(const byte *ptr, uint32 len,
DisposeAfterUse::Flag autoFree,
int rate, byte flags,
uint loopStart, uint loopEnd) {
SeekableAudioStream *stream = makeRawMemoryStream(ptr, len, autoFree, rate, flags);
const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
const bool isLooping = (flags & Audio::FLAG_LOOP) != 0;
if (isLooping) {
uint loopOffset = 0, loopLen = 0;
if (loopEnd == 0)
loopEnd = len;
assert(loopStart <= loopEnd);
assert(loopEnd <= len);
loopOffset = loopStart;
loopLen = loopEnd - loopStart;
// Verify the buffer sizes are sane
if (is16Bit && isStereo)
assert((loopLen & 3) == 0 && (loopStart & 3) == 0 && (loopEnd & 3) == 0);
else if (is16Bit || isStereo)
assert((loopLen & 1) == 0 && (loopStart & 1) == 0 && (loopEnd & 1) == 0);
const uint32 extRate = stream->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
return new SubLoopingAudioStream(stream, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
} else {
return stream;
}
}
#define MAKE_LINEAR_DISK(STEREO, UNSIGNED) \
if (is16Bit) { \
if (isLE) \
return new RawDiskStream<STEREO, true, UNSIGNED, true>(rate, disposeStream, stream, block, numBlocks); \
else \
return new RawDiskStream<STEREO, true, UNSIGNED, false>(rate, disposeStream, stream, block, numBlocks); \
} else \
return new RawDiskStream<STEREO, false, UNSIGNED, false>(rate, disposeStream, stream, block, numBlocks)
SeekableAudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block, int numBlocks,
int rate, byte flags, DisposeAfterUse::Flag disposeStream) {
const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
const bool isUnsigned = (flags & Audio::FLAG_UNSIGNED) != 0;
const bool isLE = (flags & Audio::FLAG_LITTLE_ENDIAN) != 0;
if (isStereo) {
if (isUnsigned) {
MAKE_LINEAR_DISK(true, true);
} else {
MAKE_LINEAR_DISK(true, false);
}
} else {
if (isUnsigned) {
MAKE_LINEAR_DISK(false, true);
} else {
MAKE_LINEAR_DISK(false, false);
}
}
}
AudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream, uint loopStart, uint loopEnd) {
SeekableAudioStream *s = makeRawDiskStream(stream, block, numBlocks, rate, flags, disposeStream);
const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
const bool isLooping = (flags & Audio::FLAG_LOOP) != 0;
if (isLooping) {
uint loopOffset = 0, loopLen = 0;
const uint len = s->getLength().totalNumberOfFrames() / (is16Bit ? 2 : 1) / (isStereo ? 2 : 1);
if (loopEnd == 0)
loopEnd = len;
assert(loopStart <= loopEnd);
assert(loopEnd <= len);
loopOffset = loopStart;
loopLen = loopEnd - loopStart;
// Verify the buffer sizes are sane
if (is16Bit && isStereo)
assert((loopLen & 3) == 0 && (loopStart & 3) == 0 && (loopEnd & 3) == 0);
else if (is16Bit || isStereo)
assert((loopLen & 1) == 0 && (loopStart & 1) == 0 && (loopEnd & 3) == 0);
const uint32 extRate = s->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
return new SubLoopingAudioStream(s, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
} else {
return s;
}
}
} // End of namespace Audio

View File

@ -1,144 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#ifndef SOUND_RAW_H
#define SOUND_RAW_H
#include "common/sys.h"
#include "common/types.h"
namespace Common { class SeekableReadStream; }
namespace Audio {
class AudioStream;
class SeekableAudioStream;
/**
* Various flags which can be bit-ORed and then passed to
* makeRawMemoryStream and some other AudioStream factories
* to control their behavior.
*
* Engine authors are advised not to rely on a certain value or
* order of these flags (in particular, do not store them verbatim
* in savestates).
*/
enum RawFlags {
/** unsigned samples (default: signed) */
FLAG_UNSIGNED = 1 << 0,
/** sound is 16 bits wide (default: 8bit) */
FLAG_16BITS = 1 << 1,
/** samples are little endian (default: big endian) */
FLAG_LITTLE_ENDIAN = 1 << 2,
/** sound is in stereo (default: mono) */
FLAG_STEREO = 1 << 3,
/** loop the audio */
FLAG_LOOP = 1 << 6
};
/**
* Creates a audio stream, which plays the given raw data.
*
* @param ptr Data
* @param len Length of the data (in bytes!)
* @param rate The sample rate of the data.
* @param flags Flags combination.
* @see Mixer::RawFlags
* @return The new SeekableAudioStream (or 0 on failure).
*/
SeekableAudioStream *makeRawMemoryStream(const byte *ptr, uint32 len,
DisposeAfterUse::Flag autofreeBuffer,
int rate, byte flags);
/**
* NOTE:
* This API is considered deprecated.
*
* Factory function for a raw PCM AudioStream, which will simply treat all
* data in the buffer described by ptr and len as raw sample data in the
* specified format. It will then simply pass this data directly to the mixer,
* after converting it to the sample format used by the mixer (i.e. 16 bit
* signed native endian). Optionally supports (infinite) looping of a portion
* of the data.
*/
AudioStream *makeRawMemoryStream(const byte *ptr, uint32 len,
DisposeAfterUse::Flag autofreeBuffer,
int rate, byte flags,
uint loopStart, uint loopEnd);
/**
* Struct used to define the audio data to be played by a RawDiskStream.
*/
struct RawDiskStreamAudioBlock {
int32 pos; ///< Position in stream of the block
int32 len; ///< Length of the block (in samples)
};
/**
* Creates a audio stream, which plays from given stream.
*
* @param stream Stream to play from
* @param block Pointer to an RawDiskStreamAudioBlock array
* @see RawDiskStreamAudioBlock
* @param numBlocks Number of blocks.
* @param rate The rate
* @param len Length of the data (in bytes!)
* @param flags Flags combination.
* @see Mixer::RawFlags
* @param disposeStream Whether the "stream" object should be destroyed after playback.
* @return The new SeekableAudioStream (or 0 on failure).
*/
SeekableAudioStream *makeRawDiskStream(Common::SeekableReadStream *stream,
RawDiskStreamAudioBlock *block, int numBlocks,
int rate, byte flags,
DisposeAfterUse::Flag disposeStream);
/**
* NOTE:
* This API is considered deprecated.
*
* Factory function for a Raw Disk Stream. This can stream raw PCM
* audio data from disk. The function takes an pointer to an array of
* RawDiskStreamAudioBlock which defines the start position and length of
* each block of uncompressed audio in the stream.
*/
AudioStream *makeRawDiskStream(Common::SeekableReadStream *stream,
RawDiskStreamAudioBlock *block, int numBlocks,
int rate, byte flags,
DisposeAfterUse::Flag disposeStream,
uint loopStart, uint loopEnd);
} // End of namespace Audio
#endif

View File

@ -165,6 +165,7 @@ static void drawMessage(int offset, const Common::String &text) {
surf.pixels = calloc(surf.w, surf.h);
font.drawString(&surf, text, 0, 0, surf.w, color, Graphics::kTextAlignCenter);
int y = g_system->getHeight() / 2 - font.getFontHeight() / 2 + offset * (font.getFontHeight() + 1);
// TODO implement in Residual
//g_system->copyRectToScreen((byte *)surf.pixels, surf.pitch, 0, y, surf.w, surf.h);
//g_system->updateScreen();
free(surf.pixels);
@ -282,12 +283,13 @@ int MidiDriver_MT32::open() {
171, 0, 0, 0
};
// FIXME
// TODO implement in Residual
//g_system->setPalette(dummy_palette, 0, 5);
drawMessage(-1, "Initialising MT-32 Emulator");
if (!_synth->open(prop))
return MERR_DEVICE_NOT_AVAILABLE;
_initialising = false;
// TODO implement in Residual
//g_system->fillScreen(0);
//g_system->updateScreen();
_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);

View File

@ -177,7 +177,7 @@ struct Handler : public DOSBox::Handler {
uint32 writeAddr(uint32 port, uint8 val) {
adlib_write_index(port, val);
return index;
return opl_index;
}
void generate(int16 *chan, uint samples) {

View File

@ -53,7 +53,7 @@ bool OPL::init(int rate) {
if (_opl)
MAME::OPLDestroy(_opl);
_opl = MAME::makeAdlibOPL(rate);
_opl = MAME::makeAdLibOPL(rate);
return (_opl != 0);
}
@ -1208,7 +1208,7 @@ int OPLTimerOver(FM_OPL *OPL, int c) {
return OPL->status >> 7;
}
FM_OPL *makeAdlibOPL(int rate) {
FM_OPL *makeAdLibOPL(int rate) {
// We need to emulate one YM3812 chip
int env_bits = FMOPL_ENV_BITS_HQ;
int eg_ent = FMOPL_EG_ENT_HQ;

View File

@ -173,7 +173,7 @@ void OPLWriteReg(FM_OPL *OPL, int r, int v);
void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
// Factory method
FM_OPL *makeAdlibOPL(int rate);
FM_OPL *makeAdLibOPL(int rate);
// OPL API implementation
class OPL : public ::OPL::OPL {

View File

@ -56,7 +56,7 @@ static const fltype frqmul_tab[16] = {
0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15
};
// calculated frequency multiplication values (depend on sampling rate)
static float frqmul[16];
static fltype frqmul[16];
// key scale levels
static Bit8u kslev[8][16];
@ -125,8 +125,18 @@ static Bit32u wavestart[8] = {
};
// envelope generator function constants
static fltype attackconst[4] = {1/2.82624,1/2.25280,1/1.88416,1/1.59744};
static fltype decrelconst[4] = {1/39.28064,1/31.41608,1/26.17344,1/22.44608};
static fltype attackconst[4] = {
(fltype)(1/2.82624),
(fltype)(1/2.25280),
(fltype)(1/1.88416),
(fltype)(1/1.59744)
};
static fltype decrelconst[4] = {
(fltype)(1/39.28064),
(fltype)(1/31.41608),
(fltype)(1/26.17344),
(fltype)(1/22.44608)
};
void operator_advance(op_type* op_pt, Bit32s vib) {
@ -274,9 +284,9 @@ void operator_attack(op_type* op_pt) {
op_pt->amp = 1.0;
op_pt->step_amp = 1.0;
}
op_pt->step_skip_pos <<= 1;
if (op_pt->step_skip_pos==0) op_pt->step_skip_pos = 1;
if (op_pt->step_skip_pos & op_pt->env_step_skip_a) { // check if required to skip next step
op_pt->step_skip_pos_a <<= 1;
if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1;
if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step
op_pt->step_amp = op_pt->amp;
}
}
@ -487,7 +497,7 @@ void adlib_init(Bit32u samplerate) {
op[i].env_step_a = 0;
op[i].env_step_d = 0;
op[i].env_step_r = 0;
op[i].step_skip_pos = 0;
op[i].step_skip_pos_a = 0;
op[i].env_step_skip_a = 0;
#if defined(OPLTYPE_IS_OPL3)
@ -504,7 +514,7 @@ void adlib_init(Bit32u samplerate) {
}
status = 0;
index = 0;
opl_index = 0;
// create vibrato table
@ -552,9 +562,9 @@ void adlib_init(Bit32u samplerate) {
wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC));
wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC));
wavtable[i] = wavtable[(i<<1) +WAVEPREC];
// table to be verified, alternative: (zero-less)
/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)(((i*2+1)<<1)-1)*PI/WAVEPREC));
wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)(((i*2+1)<<1) )*PI/WAVEPREC));
// alternative: (zero-less)
/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC));
wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC));
wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */
}
for (i=0;i<(WAVEPREC>>3);i++) {
@ -901,11 +911,11 @@ Bitu adlib_reg_read(Bitu port) {
}
void adlib_write_index(Bitu port, Bit8u val) {
index = val;
opl_index = val;
#if defined(OPLTYPE_IS_OPL3)
if ((port&3)!=0) {
// possibly second set
if (((adlibreg[0x105]&1)!=0) || (index==5)) index |= ARC_SECONDSET;
if (((adlibreg[0x105]&1)!=0) || (opl_index==5)) opl_index |= ARC_SECONDSET;
}
#endif
}

View File

@ -39,6 +39,13 @@
#define Bit8u uint8
#define Bit8s int8
/*
define attribution that inlines/forces inlining of a function (optional)
*/
#define OPL_INLINE INLINE
#undef NUM_CHANNELS
#if defined(OPLTYPE_IS_OPL3)
#define NUM_CHANNELS 18
@ -137,7 +144,7 @@ typedef struct operator_struct {
Bit32u generator_pos; // for non-standard sample rates we need to determine how many samples have passed
Bits cur_env_step; // current (standardized) sample position
Bits env_step_a,env_step_d,env_step_r; // number of std samples of one step (for attack/decay/release mode)
Bit8u step_skip_pos; // position of 8-cyclic step skipping (always 2^x to check against mask)
Bit8u step_skip_pos_a; // position of 8-cyclic step skipping (always 2^x to check against mask)
Bits env_step_skip_a; // bitmask that determines if a step is skipped (respective bit is zero then)
#if defined(OPLTYPE_IS_OPL3)
@ -153,7 +160,7 @@ op_type op[MAXOPERATORS];
Bits int_samplerate;
Bit8u status;
Bit32u index;
Bit32u opl_index;
#if defined(OPLTYPE_IS_OPL3)
Bit8u adlibreg[512]; // adlib register set (including second set)
Bit8u wave_sel[44]; // waveform selection

View File

@ -1275,7 +1275,7 @@ void SID::enable_external_filter(bool enable) {
* E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not
* be set lower than ~ 8kHz. A lower sample frequency would make the
* resampling code overfill its 16k sample ring buffer.
*
*
* The end of passband frequency is also limited:
* pass_freq <= 0.9*sample_freq/2
*

View File

@ -1,250 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
#include "sound/vorbis.h"
#ifdef USE_VORBIS
#include "common/debug.h"
#include "common/stream.h"
#include "common/util.h"
#include "sound/audiostream.h"
#include "sound/audiocd.h"
#ifdef USE_TREMOR
#ifdef __GP32__ // GP32 uses custom libtremor
#include <ivorbisfile.h>
#else
#include <tremor/ivorbisfile.h>
#endif
#else
#include <vorbis/vorbisfile.h>
#endif
namespace Audio {
// These are wrapper functions to allow using a SeekableReadStream object to
// provide data to the OggVorbis_File object.
static size_t read_stream_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) {
Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
uint32 result = stream->read(ptr, size * nmemb);
return result / size;
}
static int seek_stream_wrap(void *datasource, ogg_int64_t offset, int whence) {
Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
stream->seek((int32)offset, whence);
return stream->pos();
}
static int close_stream_wrap(void *datasource) {
// Do nothing -- we leave it up to the VorbisInputStream to free memory as appropriate.
return 0;
}
static long tell_stream_wrap(void *datasource) {
Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
return stream->pos();
}
static ov_callbacks g_stream_wrap = {
read_stream_wrap, seek_stream_wrap, close_stream_wrap, tell_stream_wrap
};
#pragma mark -
#pragma mark --- Ogg Vorbis stream ---
#pragma mark -
class VorbisInputStream : public SeekableAudioStream {
protected:
Common::SeekableReadStream *_inStream;
DisposeAfterUse::Flag _disposeAfterUse;
bool _isStereo;
int _rate;
Timestamp _length;
OggVorbis_File _ovFile;
int16 _buffer[4096];
const int16 *_bufferEnd;
const int16 *_pos;
public:
// startTime / duration are in milliseconds
VorbisInputStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose);
~VorbisInputStream();
int readBuffer(int16 *buffer, const int numSamples);
bool endOfData() const { return _pos >= _bufferEnd; }
bool isStereo() const { return _isStereo; }
int getRate() const { return _rate; }
bool seek(const Timestamp &where);
Timestamp getLength() const { return _length; }
protected:
bool refill();
};
VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
_inStream(inStream),
_disposeAfterUse(dispose),
_length(0, 1000),
_bufferEnd(_buffer + ARRAYSIZE(_buffer)) {
int res = ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap);
if (res < 0) {
warning("Could not create Vorbis stream (%d)", res);
_pos = _bufferEnd;
return;
}
// Read in initial data
if (!refill())
return;
// Setup some header information
_isStereo = ov_info(&_ovFile, -1)->channels >= 2;
_rate = ov_info(&_ovFile, -1)->rate;
#ifdef USE_TREMOR
_length = Timestamp(ov_time_total(&_ovFile, -1), getRate());
#else
_length = Timestamp(uint32(ov_time_total(&_ovFile, -1) * 1000.0), getRate());
#endif
}
VorbisInputStream::~VorbisInputStream() {
ov_clear(&_ovFile);
if (_disposeAfterUse == DisposeAfterUse::YES)
delete _inStream;
}
int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
while (samples < numSamples && _pos < _bufferEnd) {
const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
memcpy(buffer, _pos, len * 2);
buffer += len;
_pos += len;
samples += len;
if (_pos >= _bufferEnd) {
if (!refill())
break;
}
}
return samples;
}
bool VorbisInputStream::seek(const Timestamp &where) {
int res = ov_pcm_seek(&_ovFile, calculateSampleOffset(where, getRate()));
if (res) {
warning("Error seeking in Vorbis stream (%d)", res);
_pos = _bufferEnd;
return false;
}
return refill();
}
bool VorbisInputStream::refill() {
// Read the samples
uint len_left = sizeof(_buffer);
char *read_pos = (char *)_buffer;
while (len_left > 0) {
long result;
#ifdef USE_TREMOR
// Tremor ov_read() always returns data as signed 16 bit interleaved PCM
// in host byte order. As such, it does not take arguments to request
// specific signedness, byte order or bit depth as in Vorbisfile.
result = ov_read(&_ovFile, read_pos, len_left,
NULL);
#else
#ifdef SCUMM_BIG_ENDIAN
result = ov_read(&_ovFile, read_pos, len_left,
1,
2, // 16 bit
1, // signed
NULL);
#else
result = ov_read(&_ovFile, read_pos, len_left,
0,
2, // 16 bit
1, // signed
NULL);
#endif
#endif
if (result == OV_HOLE) {
// Possibly recoverable, just warn about it
warning("Corrupted data in Vorbis file");
} else if (result == 0) {
//warning("End of file while reading from Vorbis file");
//_pos = _bufferEnd;
//return false;
break;
} else if (result < 0) {
warning("Error reading from Vorbis stream (%d)", int(result));
_pos = _bufferEnd;
// Don't delete it yet, that causes problems in
// the CD player emulation code.
return false;
} else {
len_left -= result;
read_pos += result;
}
}
_pos = _buffer;
_bufferEnd = (int16 *)read_pos;
return true;
}
#pragma mark -
#pragma mark --- Ogg Vorbis factory functions ---
#pragma mark -
SeekableAudioStream *makeVorbisStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse) {
return new VorbisInputStream(stream, disposeAfterUse);
}
} // End of namespace Audio
#endif // #ifdef USE_VORBIS

View File

@ -1,73 +0,0 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*
*/
/**
* @file
* Sound decoder used in engines:
* - agos
* - kyra
* - m4
* - queen
* - saga
* - scumm
* - sword1
* - sword2
* - touche
* - tucker
*/
#ifndef SOUND_VORBIS_H
#define SOUND_VORBIS_H
#include "common/types.h"
#include "common/sys.h"
#ifdef USE_VORBIS
namespace Common {
class SeekableReadStream;
}
namespace Audio {
class AudioStream;
class SeekableAudioStream;
/**
* Create a new SeekableAudioStream from the Ogg Vorbis data in the given stream.
* Allows for seeking (which is why we require a SeekableReadStream).
*
* @param stream the SeekableReadStream from which to read the Ogg Vorbis data
* @param disposeAfterUse whether to delete the stream after use
* @return a new SeekableAudioStream, or NULL, if an error occured
*/
SeekableAudioStream *makeVorbisStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse);
} // End of namespace Audio
#endif // #ifdef USE_VORBIS
#endif // #ifndef SOUND_VORBIS_H

View File

@ -69,11 +69,13 @@ sub html_entities_to_ascii {
# &uuml; -> ue
# &amp; -> &
# &#322; -> l
# &Scaron; -> S
$text =~ s/&aacute;/a/g;
$text =~ s/&eacute;/e/g;
$text =~ s/&oacute;/o/g;
$text =~ s/&oslash;/o/g;
$text =~ s/&#322;/l/g;
$text =~ s/&Scaron;/S/g;
$text =~ s/&auml;/a/g;
$text =~ s/&uuml;/ue/g;
@ -95,6 +97,7 @@ sub html_entities_to_cpp {
$text =~ s/&oacute;/\\363/g;
$text =~ s/&oslash;/\\370/g;
$text =~ s/&#322;/l/g;
$text =~ s/&Scaron;/\\352/g;
$text =~ s/&auml;/\\344/g;
$text =~ s/&ouml;/\\366/g;
@ -114,6 +117,7 @@ sub html_entities_to_rtf {
$text =~ s/&oacute;/\\'97/g;
$text =~ s/&oslash;/\\'bf/g;
$text =~ s/&#322;/\\uc0\\u322 /g;
$text =~ s/&Scaron;/\\uc0\\u352 /g;
$text =~ s/&auml;/\\'8a/g;
$text =~ s/&ouml;/\\'9a/g;
@ -133,6 +137,7 @@ sub html_entities_to_tex {
$text =~ s/&oacute;/\\'o/g;
$text =~ s/&oslash;/{\\o}/g;
$text =~ s/&#322;/{\\l}/g;
$text =~ s/&Scaron;/{\\v S}/g;
$text =~ s/&auml;/\\"a/g;
$text =~ s/&ouml;/\\"o/g;
@ -428,15 +433,18 @@ sub add_paragraph {
print wrap($tab, $tab, html_entities_to_ascii($text))."\n";
print "\n";
} elsif ($mode eq "TEX") {
$text = html_entities_to_tex($text);
print '\item' . "\n";
print $text;
print "\n";
} elsif ($mode eq "RTF") {
$text = html_entities_to_rtf($text);
# Center text
print '\pard\qc' . "\n";
print "\\\n";
print $text . "\\\n";
} elsif ($mode eq "CPP") {
$text = html_entities_to_ascii($text);
my $line_start = '"C0""';
my $line_end = '",';
print $line_start . $text . $line_end . "\n";