synced imuse digital with scummvm imuse and related stuff

This commit is contained in:
Pawel Kolodziejski 2008-03-10 23:06:07 +00:00
parent 857527b278
commit f11e24b7b1
32 changed files with 1536 additions and 781 deletions

52
common/frac.h Normal file
View File

@ -0,0 +1,52 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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_FRAC_H
#define COMMON_FRAC_H
#include "common/sys.h"
/**
* The precision of the fractional (fixed point) type we define below.
* Normally you should never have to modify this value.
*/
enum {
FRAC_BITS = 16,
FRAC_LO_MASK = ((1L << FRAC_BITS) - 1),
FRAC_HI_MASK = ((1L << FRAC_BITS) - 1) << FRAC_BITS,
FRAC_ONE = (1L << FRAC_BITS), // 1.0
FRAC_HALF = (1L << (FRAC_BITS-1)) // 0.5
};
/**
* Fixed-point fractions, used by the sound rate converter and other code.
*/
typedef int32 frac_t;
inline frac_t doubleToFrac(double value) { return (frac_t)(value * FRAC_ONE); }
inline double fracToDouble(frac_t value) { return ((double)value) / FRAC_ONE; }
inline frac_t intToFrac(int16 value) { return value << FRAC_BITS; }
inline int16 fracToInt(frac_t value) { return value >> FRAC_BITS; }
#endif

264
common/list.h Normal file
View File

@ -0,0 +1,264 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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_LIST_H
#define COMMON_LIST_H
#include "common/sys.h"
namespace Common {
/**
* Simple double linked list, modeled after the list template of the standard
* C++ library.
*/
template <class t_T>
class List {
protected:
#if defined (_WIN32_WCE) || defined (_MSC_VER)
//FIXME evc4 and msvc7 doesn't like it as protected member
public:
#endif
struct NodeBase {
NodeBase *_prev;
NodeBase *_next;
};
template <class t_T2>
struct Node : public NodeBase {
t_T2 _data;
Node(const t_T2 &x) : _data(x) {}
};
template <class t_T2>
class Iterator {
friend class List<t_T>;
NodeBase *_node;
#if !defined (__WINSCW__)
explicit Iterator(NodeBase *node) : _node(node) {}
#else
Iterator(NodeBase *node) : _node(node) {}
#endif
public:
Iterator() : _node(0) {}
// Prefix inc
Iterator<t_T2> &operator++() {
if (_node)
_node = _node->_next;
return *this;
}
// Postfix inc
Iterator<t_T2> operator++(int) {
Iterator tmp(_node);
++(*this);
return tmp;
}
// Prefix dec
Iterator<t_T2> &operator--() {
if (_node)
_node = _node->_prev;
return *this;
}
// Postfix dec
Iterator<t_T2> operator--(int) {
Iterator tmp(_node);
--(*this);
return tmp;
}
t_T2& operator*() const {
assert(_node);
#if (__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)
return static_cast<List<t_T>::Node<t_T2> *>(_node)->_data;
#else
return static_cast<Node<t_T2>*>(_node)->_data;
#endif
}
t_T2* operator->() const {
return &(operator*());
}
bool operator==(const Iterator<t_T2>& x) const {
return _node == x._node;
}
bool operator!=(const Iterator<t_T2>& x) const {
return _node != x._node;
}
};
NodeBase *_anchor;
public:
typedef Iterator<t_T> iterator;
typedef Iterator<const t_T> const_iterator;
typedef t_T value_type;
public:
List() {
_anchor = new NodeBase;
_anchor->_prev = _anchor;
_anchor->_next = _anchor;
}
List(const List<t_T>& list) {
_anchor = new NodeBase;
_anchor->_prev = _anchor;
_anchor->_next = _anchor;
insert(begin(), list.begin(), list.end());
}
~List() {
clear();
delete _anchor;
}
void push_front(const t_T& element) {
insert(begin(), element);
}
void push_back(const t_T& element) {
insert(end(), element);
}
void insert(iterator pos, const t_T& element) {
NodeBase *newNode = new Node<t_T>(element);
newNode->_next = pos._node;
newNode->_prev = pos._node->_prev;
newNode->_prev->_next = newNode;
newNode->_next->_prev = newNode;
}
template <typename iterator2>
void insert(iterator pos, iterator2 first, iterator2 last) {
for (; first != last; ++first)
insert(pos, *first);
}
iterator erase(iterator pos) {
assert(pos != end());
NodeBase *next = pos._node->_next;
NodeBase *prev = pos._node->_prev;
Node<t_T> *node = static_cast<Node<t_T> *>(pos._node);
prev->_next = next;
next->_prev = prev;
delete node;
return iterator(next);
}
iterator reverse_erase(iterator pos) {
assert(pos != end());
NodeBase *next = pos._node->_next;
NodeBase *prev = pos._node->_prev;
Node<t_T> *node = static_cast<Node<t_T> *>(pos._node);
prev->_next = next;
next->_prev = prev;
delete node;
return iterator(prev);
}
iterator erase(iterator first, iterator last) {
while (first != last)
erase(first++);
return last;
}
void remove(const t_T &val) {
iterator i = begin();
while (i != end())
if (val == i.operator*())
i = erase(i);
else
++i;
}
List<t_T>& operator =(const List<t_T>& list) {
if (this != &list) {
iterator i;
const_iterator j;
for (i = begin(), j = list.begin(); (i != end()) && (j != list.end()) ; ++i, ++j) {
static_cast<Node<t_T> *>(i._node)->_data = static_cast<Node<t_T> *>(j._node)->_data;
}
if (i == end())
insert(i, j, list.end());
else
erase(i, end());
}
return *this;
}
uint size() const {
int n = 0;
for (const_iterator i = begin(); i != end(); ++i)
++n;
return n;
}
void clear() {
erase(begin(), end());
}
bool empty() const {
return (_anchor == _anchor->_next);
}
iterator begin() {
return iterator(_anchor->_next);
}
iterator reverse_begin() {
return iterator(_anchor->_prev);
}
iterator end() {
return iterator(_anchor);
}
const_iterator begin() const {
return const_iterator(_anchor->_next);
}
const_iterator reverse_begin() const {
return const_iterator(_anchor->_prev);
}
const_iterator end() const {
return const_iterator(_anchor);
}
};
} // End of namespace Common
#endif

72
common/mutex.cpp Normal file
View File

@ -0,0 +1,72 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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/mutex.h"
#include "common/debug.h"
#include "engine/backend/driver.h"
namespace Common {
Mutex::Mutex() {
_mutex = g_driver->createMutex();
}
Mutex::~Mutex() {
g_driver->deleteMutex(_mutex);
}
void Mutex::lock() {
g_driver->lockMutex(_mutex);
}
void Mutex::unlock() {
g_driver->unlockMutex(_mutex);
}
#pragma mark -
StackLock::StackLock(MutexRef mutex, const char *mutexName)
: _mutex(mutex), _mutexName(mutexName) {
lock();
}
StackLock::StackLock(const Mutex &mutex, const char *mutexName)
: _mutex(mutex._mutex), _mutexName(mutexName) {
lock();
}
StackLock::~StackLock() {
unlock();
}
void StackLock::lock() {
g_driver->lockMutex(_mutex);
}
void StackLock::unlock() {
g_driver->unlockMutex(_mutex);
}
} // End of namespace Common

73
common/mutex.h Normal file
View File

@ -0,0 +1,73 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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_MUTEX_H
#define COMMON_MUTEX_H
#include "common/sys.h"
namespace Common {
class Mutex;
/**
* An pseudo-opaque mutex type.
*/
typedef struct OpaqueMutex *MutexRef;
/**
* Auxillary class to (un)lock a mutex on the stack.
*/
class StackLock {
MutexRef _mutex;
const char *_mutexName;
void lock();
void unlock();
public:
StackLock(MutexRef mutex, const char *mutexName = NULL);
StackLock(const Mutex &mutex, const char *mutexName = NULL);
~StackLock();
};
/**
* Wrapper class.
*/
class Mutex {
friend class StackLock;
MutexRef _mutex;
public:
Mutex();
~Mutex();
void lock();
void unlock();
};
} // End of namespace Common
#endif

43
common/noncopyable.h Normal file
View File

@ -0,0 +1,43 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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_NONCOPYABLE_H
#define COMMON_NONCOPYABLE_H
namespace Common {
/**
* Subclass of NonCopyable can not be copied due to the fact that
* we made the copy constructor and assigment operator private.
*/
class NonCopyable {
public:
NonCopyable() {}
private:
// Prevent copying instances by accident
NonCopyable(const NonCopyable&);
NonCopyable& operator= (const NonCopyable&);
};
} // End of namespace Common
#endif

View File

@ -24,8 +24,6 @@
#define COMMON_SYS_H
typedef struct Mutex *MutexRef;
#ifndef _MSC_VER
#include <unistd.h>
#endif

View File

@ -1,135 +0,0 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* $URL$
* $Id$
*
*/
#include "common/sys.h"
#include "common/platform.h"
#include "common/debug.h"
#include "common/timer.h"
#include "engine/backend/driver.h"
Timer *g_timer = NULL;
Timer::Timer() :
_mutex(0),
_timerHandler(0),
_lastTime(0) {
_mutex = g_driver->createMutex();
g_timer = this;
for (int i = 0; i < MAX_TIMERS; i++) {
_timerSlots[i].procedure = NULL;
_timerSlots[i].interval = 0;
_timerSlots[i].counter = 0;
}
_thisTime = g_driver->getMillis();
// Set the timer last, after everything has been initialised
g_driver->setTimerCallback(timer_handler, 10);
}
Timer::~Timer() {
g_driver->setTimerCallback(NULL, 0);
{
StackLock lock(_mutex);
for (int i = 0; i < MAX_TIMERS; i++) {
_timerSlots[i].procedure = NULL;
_timerSlots[i].interval = 0;
_timerSlots[i].counter = 0;
}
}
g_driver->deleteMutex(_mutex);
}
int Timer::timer_handler(int t) {
if (g_timer)
return g_timer->handler(t);
return 0;
}
int Timer::handler(int t) {
StackLock lock(_mutex);
uint32 interval, l;
_lastTime = _thisTime;
_thisTime = g_driver->getMillis();
interval = 1000 * (_thisTime - _lastTime);
// If the timer has been frozen for a long time, don't
// call the procedures a silly number of times, just resynchronize
if(interval > 1000000) {
interval = 0;
warning("Timer skipped forward");
}
for (l = 0; l < MAX_TIMERS; l++) {
if (_timerSlots[l].procedure && _timerSlots[l].interval > 0) {
_timerSlots[l].counter -= interval;
while (_timerSlots[l].counter <= 0) {
// A small paranoia check which catches the case where
// a timer removes itself (which it never should do).
assert(_timerSlots[l].procedure && _timerSlots[l].interval > 0);
_timerSlots[l].counter += _timerSlots[l].interval;
_timerSlots[l].procedure(_timerSlots[l].refCon);
}
}
}
return t;
}
bool Timer::installTimerProc(TimerProc procedure, int32 interval, void *refCon) {
assert(interval > 0);
StackLock lock(_mutex);
for (int l = 0; l < MAX_TIMERS; l++) {
if (!_timerSlots[l].procedure) {
_timerSlots[l].procedure = procedure;
_timerSlots[l].interval = interval;
_timerSlots[l].counter = interval;
_timerSlots[l].refCon = refCon;
return true;
}
}
if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
warning("Couldn't find free timer slot!");
return false;
}
void Timer::removeTimerProc(TimerProc procedure) {
StackLock lock(_mutex);
for (int l = 0; l < MAX_TIMERS; l++) {
if (_timerSlots[l].procedure == procedure) {
_timerSlots[l].procedure = 0;
_timerSlots[l].interval = 0;
_timerSlots[l].counter = 0;
_timerSlots[l].refCon = 0;
}
}
}

View File

@ -1,19 +1,19 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* 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 library is distributed in the hope that it will be useful,
* 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
* Lesser General Public License for more details.
* 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 Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
* 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$
@ -24,30 +24,15 @@
#define COMMON_TIMER_H
#include "common/sys.h"
#include "common/platform.h"
#include "common/noncopyable.h"
#define MAX_TIMERS 3
typedef void (*TimerProc)(void *refCon);
class Timer {
private:
MutexRef _mutex;
void *_timerHandler;
int32 _thisTime;
int32 _lastTime;
struct TimerSlots {
TimerProc procedure;
int32 interval;
int32 counter;
void *refCon;
} _timerSlots[MAX_TIMERS];
namespace Common {
class TimerManager : NonCopyable {
public:
Timer();
~Timer();
typedef void (*TimerProc)(void *refCon);
virtual ~TimerManager() {}
/**
* Install a new timer callback. It will from now be called every interval microseconds.
@ -61,19 +46,14 @@ public:
* @param refCon an arbitrary void pointer; will be passed to the timer callback
* @return true if the timer was installed successfully, false otherwise
*/
bool installTimerProc(TimerProc proc, int32 interval, void *refCon);
virtual bool installTimerProc(TimerProc proc, int32 interval, void *refCon) = 0;
/**
* Remove the given timer callback. It will not be invoked anymore.
*/
void removeTimerProc(TimerProc proc);
protected:
static int timer_handler(int t);
int handler(int t);
virtual void removeTimerProc(TimerProc proc) = 0;
};
extern Timer *g_timer;
} // End of namespace Common
#endif

View File

@ -198,6 +198,14 @@
RelativePath="..\..\common\debug.h"
>
</File>
<File
RelativePath="..\..\common\frac.h"
>
</File>
<File
RelativePath="..\..\common\list.h"
>
</File>
<File
RelativePath="..\..\common\matrix3.cpp"
>
@ -214,6 +222,18 @@
RelativePath="..\..\common\matrix4.h"
>
</File>
<File
RelativePath="..\..\common\mutex.cpp"
>
</File>
<File
RelativePath="..\..\common\mutex.h"
>
</File>
<File
RelativePath="..\..\common\noncopyable.h"
>
</File>
<File
RelativePath="..\..\common\platform.h"
>
@ -222,10 +242,6 @@
RelativePath="..\..\common\sys.h"
>
</File>
<File
RelativePath="..\..\common\timer.cpp"
>
</File>
<File
RelativePath="..\..\common\timer.h"
>
@ -781,10 +797,18 @@
RelativePath="..\..\engine\imuse\imuse_tables.cpp"
>
</File>
<File
RelativePath="..\..\engine\imuse\imuse_tables.h"
>
</File>
<File
RelativePath="..\..\engine\imuse\imuse_track.cpp"
>
</File>
<File
RelativePath="..\..\engine\imuse\imuse_track.h"
>
</File>
</Filter>
<Filter
Name="smush"
@ -813,6 +837,14 @@
<Filter
Name="backend"
>
<File
RelativePath="..\..\engine\backend\default-timer.cpp"
>
</File>
<File
RelativePath="..\..\engine\backend\default-timer.h"
>
</File>
<File
RelativePath="..\..\engine\backend\driver.h"
>

View File

@ -0,0 +1,144 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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/sys.h"
#include "engine/backend/driver.h"
#include "engine/backend/default-timer.h"
struct TimerSlot {
Common::TimerManager::TimerProc callback;
void *refCon;
uint32 interval; // in microseconds
uint32 nextFireTime; // in milliseconds
uint32 nextFireTimeMicro; // mircoseconds part of nextFire
TimerSlot *next;
};
void insertPrioQueue(TimerSlot *head, TimerSlot *newSlot) {
// The head points to a fake anchor TimerSlot; this common
// trick allows us to get rid of many special cases.
const uint32 nextFireTime = newSlot->nextFireTime;
TimerSlot *slot = head;
newSlot->next = 0;
// Insert the new slot into the sorted list of already scheduled
// timers in such a way that the list stays sorted...
while (true) {
assert(slot);
if (slot->next == 0 || nextFireTime < slot->next->nextFireTime) {
newSlot->next = slot->next;
slot->next = newSlot;
return;
}
slot = slot->next;
}
}
DefaultTimerManager::DefaultTimerManager() :
_timerHandler(0),
_head(0) {
_head = new TimerSlot();
memset(_head, 0, sizeof(TimerSlot));
}
DefaultTimerManager::~DefaultTimerManager() {
Common::StackLock lock(_mutex);
TimerSlot *slot = _head;
while (slot) {
TimerSlot *next = slot->next;
delete slot;
slot = next;
}
_head = 0;
}
void DefaultTimerManager::handler() {
Common::StackLock lock(_mutex);
const uint32 curTime = g_driver->getMillis();
// Repeat as long as there is a TimerSlot that is scheduled to fire.
TimerSlot *slot = _head->next;
while (slot && slot->nextFireTime < curTime) {
// Remove the slot from the priority queue
_head->next = slot->next;
// Update the fire time and reinsert the TimerSlot into the priority
// queue. Has to be done before the timer callback is invoked, in case
// the callback wants to remove itself.
assert(slot->interval > 0);
slot->nextFireTime += (slot->interval / 1000);
slot->nextFireTimeMicro += (slot->interval % 1000);
if (slot->nextFireTimeMicro > 1000) {
slot->nextFireTime += slot->nextFireTimeMicro / 1000;
slot->nextFireTimeMicro %= 1000;
}
insertPrioQueue(_head, slot);
// Invoke the timer callback
assert(slot->callback);
slot->callback(slot->refCon);
// Look at the next scheduled timer
slot = _head->next;
}
}
bool DefaultTimerManager::installTimerProc(TimerProc callback, int32 interval, void *refCon) {
assert(interval > 0);
Common::StackLock lock(_mutex);
TimerSlot *slot = new TimerSlot;
slot->callback = callback;
slot->refCon = refCon;
slot->interval = interval;
slot->nextFireTime = g_driver->getMillis() + interval / 1000;
slot->nextFireTimeMicro = interval % 1000;
slot->next = 0;
insertPrioQueue(_head, slot);
return true;
}
void DefaultTimerManager::removeTimerProc(TimerProc callback) {
Common::StackLock lock(_mutex);
TimerSlot *slot = _head;
while (slot->next) {
if (slot->next->callback == callback) {
TimerSlot *next = slot->next->next;
delete slot->next;
slot->next = next;
} else {
slot = slot->next;
}
}
}

View File

@ -0,0 +1,48 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2008 The ScummVM-Residual Team (www.scummvm.org)
*
* 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 BACKENDS_TIMER_DEFAULT_H
#define BACKENDS_TIMER_DEFAULT_H
#include "common/timer.h"
#include "common/mutex.h"
struct TimerSlot;
class DefaultTimerManager : public Common::TimerManager {
private:
Common::Mutex _mutex;
void *_timerHandler;
TimerSlot *_head;
public:
DefaultTimerManager();
~DefaultTimerManager();
bool installTimerProc(TimerProc proc, int32 interval, void *refCon);
void removeTimerProc(TimerProc proc);
// Timer callback, to be invoked at regular time intervals by the backend.
void handler();
};
#endif

View File

@ -25,6 +25,7 @@
#include "common/platform.h"
#include "common/vector3d.h"
#include "common/mutex.h"
#include "engine/color.h"
#include "engine/model.h"
@ -33,9 +34,15 @@
#include "engine/font.h"
#include "engine/primitives.h"
#include "engine/actor.h"
#include "engine/backend/default-timer.h"
class Material;
class Bitmap;
class Timer;
namespace Audio {
class Mixer;
}
class Driver {
public:
@ -116,7 +123,7 @@ public:
/** @name Events and Time */
//@{
typedef int (*TimerProc)(int interval);
typedef unsigned int (*TimerProc)(unsigned int interval, void *param);
/**
* The types of events backends may generate.
@ -239,25 +246,22 @@ public:
* @param interval the interval (in milliseconds) between invocations
* of the callback
*/
virtual void setTimerCallback(TimerProc callback, int interval) = 0;
virtual void setTimerCallback() = 0;
virtual void clearTimerCallback() = 0;
//@}
/**
* @name Mutex handling
* Historically, the OSystem API used to have a method which allowed
* creating threads. Hence mutex support was needed for thread syncing.
* To ease portability, though, we decided to remove the threading API.
* Instead, we now use timers (see setTimerCallback() and Timer).
* But since those may be implemented using threads (and in fact, that's
* how our primary backend, the SDL one, does it on many systems), we
* still have to do mutex syncing in our timer callbacks.
*
* Hence backends which do not use threads to implement the timers simply
* can use dummy implementations for these methods.
*/
//@{
typedef Common::MutexRef MutexRef;
/**
* Create a new mutex.
* @return the newly created mutex, or 0 if an error occured.
@ -266,6 +270,12 @@ public:
/**
* Lock the given mutex.
*
* @note Code assumes that the mutex implementation supports
* recursive locking. That is, a thread may lock a mutex twice w/o
* deadlocking. In case of a multilock, the mutex has to be unlocked
* as many times as it was locked befored it really becomes unlocked.
*
* @param mutex the mutex to lock.
*/
virtual void lockMutex(MutexRef mutex) = 0;
@ -329,16 +339,7 @@ protected:
};
extern Driver *g_driver;
class StackLock {
MutexRef _mutex;
public:
StackLock(MutexRef mutex) : _mutex(mutex) {
g_driver->lockMutex(_mutex);
}
~StackLock() {
g_driver->unlockMutex(_mutex);
}
};
extern DefaultTimerManager *g_timer;
extern Audio::Mixer *g_mixer;
#endif

View File

@ -359,11 +359,22 @@ void DriverSDL::delayMillis(uint msecs) {
SDL_Delay(msecs);
}
void DriverSDL::setTimerCallback(TimerProc callback, int timer) {
SDL_SetTimer(timer, (SDL_TimerCallback) callback);
static SDL_TimerID _timerID = NULL;
static Uint32 timer_handler(Uint32 interval, void *param) {
((DefaultTimerManager *)param)->handler();
return interval;
}
MutexRef DriverSDL::createMutex() {
void DriverSDL::setTimerCallback() {
_timerID = SDL_AddTimer(10, &timer_handler, g_timer);
}
void DriverSDL::clearTimerCallback() {
SDL_RemoveTimer(_timerID);
}
Common::MutexRef DriverSDL::createMutex() {
return (MutexRef)SDL_CreateMutex();
}
@ -382,12 +393,20 @@ void DriverSDL::deleteMutex(MutexRef mutex) {
bool DriverSDL::setSoundCallback(SoundProc proc, void *param) {
SDL_AudioSpec desired;
// Determine the sample buffer size. We want it to store enough data for
// about 1/10th of a second. Note that it must be a power of two.
// So e.g. at 22050 Hz, we request a sample buffer size of 2048.
int samples = 0x8000;
while (10 * samples >= _samplesPerSec) {
samples >>= 1;
}
memset(&desired, 0, sizeof(desired));
desired.freq = _samplesPerSec;
desired.format = AUDIO_S16SYS;
desired.channels = 2;
desired.samples = 2048;
desired.samples = (uint16)samples;
desired.callback = proc;
desired.userdata = param;

View File

@ -52,7 +52,8 @@ public:
bool pollEvent(Event &event);
uint32 getMillis();
void delayMillis(uint msecs);
void setTimerCallback(TimerProc callback, int interval);
void setTimerCallback();
void clearTimerCallback();
MutexRef createMutex();
void lockMutex(MutexRef mutex);

View File

@ -42,7 +42,7 @@ Font::Font(const char *filename, const char *data, int /*len*/) :
data += 32;
// Read character indexes - are the key/value reversed?
_charIndex = (uint16 *)malloc(sizeof(_charIndex) * _numChars);
_charIndex = new uint16[_numChars];
if (!_charIndex)
error("Could not load font %s. Out of memory\n", filename);
for (uint i = 0; i < _numChars; ++i) {
@ -52,7 +52,7 @@ Font::Font(const char *filename, const char *data, int /*len*/) :
data += _numChars * 2;
// Read character headers
_charHeaders = (CharHeader *)malloc(sizeof(CharHeader) * _numChars);
_charHeaders = new CharHeader[_numChars];
if (!_charHeaders)
error("Could not load font %s. Out of memory\n", filename);
for (uint i = 0; i < _numChars; ++i) {
@ -65,7 +65,7 @@ Font::Font(const char *filename, const char *data, int /*len*/) :
data += 16;
}
// Read font data
_fontData = (byte *)malloc(_dataSize);
_fontData = new byte[_dataSize];
if (!_fontData)
error("Could not load font %s. Out of memory\n", filename);
@ -73,9 +73,9 @@ Font::Font(const char *filename, const char *data, int /*len*/) :
}
Font::~Font() {
free(_charIndex);
free(_charHeaders);
free(_fontData);
delete[] _charIndex;
delete[] _charHeaders;
delete[] _fontData;
}
uint16 Font::getCharIndex(unsigned char c) {

View File

@ -24,6 +24,7 @@
#include "common/platform.h"
#include "common/debug.h"
#include "common/timer.h"
#include "common/mutex.h"
#include "engine/engine.h"
#include "engine/savegame.h"
@ -42,26 +43,20 @@ extern ImuseTable grimSeqMusicTable[];
extern ImuseTable grimDemoStateMusicTable[];
extern ImuseTable grimDemoSeqMusicTable[];
Imuse::Track::Track()
: used(false), stream(NULL) {
}
void Imuse::timerHandler(void *refCon) {
Imuse *imuse = (Imuse *)refCon;
imuse->callback();
}
Imuse::Imuse(int fps) {
_mutex = g_driver->createMutex();
_pause = false;
_sound = new ImuseSndMgr();
_volVoice = 0;
_volSfx = 0;
_volMusic = 0;
assert(_sound);
_callbackFps = fps;
resetState();
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
_track[l] = new Track;
assert(_track[l]);
_track[l]->trackId = l;
_track[l]->used = false;
strcpy(_track[l]->soundName, "");
@ -73,13 +68,12 @@ Imuse::Imuse(int fps) {
}
Imuse::~Imuse() {
stopAllSounds();
g_timer->removeTimerProc(timerHandler);
stopAllSounds();
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
delete _track[l];
}
delete _sound;
g_driver->deleteMutex(_mutex);
}
void Imuse::resetState() {
@ -89,19 +83,18 @@ void Imuse::resetState() {
}
void Imuse::restoreState(SaveGame *savedState) {
StackLock lock(_mutex);
Common::StackLock lock(_mutex);
printf("Imuse::restoreState() started.\n");
savedState->beginSection('IMUS');
savedState->read(&_volVoice, sizeof(int32));
savedState->read(&_volSfx, sizeof(int32));
savedState->read(&_volMusic, sizeof(int32));
savedState->read(&_curMusicState, sizeof(int32));
savedState->read(&_curMusicSeq, sizeof(int32));
savedState->read(_attributes, sizeof(int32) * 185);
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
Track *track = _track[l];
memset(track, 0, sizeof(Track));
track->trackId = l;
savedState->read(&track->pan, sizeof(int32));
savedState->read(&track->panFadeDest, sizeof(int32));
savedState->read(&track->panFadeDelay, sizeof(int32));
@ -113,50 +106,51 @@ void Imuse::restoreState(SaveGame *savedState) {
savedState->read(track->soundName, 32);
savedState->read(&track->used, sizeof(bool));
savedState->read(&track->toBeRemoved, sizeof(bool));
savedState->read(&track->readyToRemove, sizeof(bool));
savedState->read(&track->started, sizeof(bool));
savedState->read(&track->priority, sizeof(int32));
savedState->read(&track->regionOffset, sizeof(int32));
savedState->read(&track->dataOffset, sizeof(int32));
savedState->read(&track->curRegion, sizeof(int32));
savedState->read(&track->curHookId, sizeof(int32));
savedState->read(&track->volGroupId, sizeof(int32));
savedState->read(&track->iteration, sizeof(int32));
savedState->read(&track->feedSize, sizeof(int32));
savedState->read(&track->mixerFlags, sizeof(int32));
savedState->read(&track->mixerVol, sizeof(int32));
savedState->read(&track->mixerPan, sizeof(int32));
if (!track->used)
continue;
track->readyToRemove = false;
if (track->toBeRemoved) {
track->stream = NULL;
if (track->toBeRemoved || track->curRegion == -1) {
track->used = false;
continue;
}
track->soundHandle = _sound->openSound(track->soundName, track->volGroupId);
assert(track->soundHandle);
track->soundDesc = _sound->openSound(track->soundName, track->volGroupId);
if (!track->soundDesc) {
warning("Imuse::restoreState: Can't open sound so will not be resumed");
track->used = false;
continue;
}
int32 streamBufferSize = track->iteration;
int freq = _sound->getFreq(track->soundHandle);
int channels = _sound->getChannels(track->soundDesc);
int freq = _sound->getFreq(track->soundDesc);
track->mixerFlags = kFlag16Bits;
if (channels == 2)
track->mixerFlags |= kFlagStereo | kFlagReverseStereo;
track->stream = makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
g_mixer->playInputStream(&track->handle, track->stream, false, -1, track->mixerVol, track->mixerPan, false);
track->stream = Audio::makeAppendableAudioStream(freq, makeMixerFlags(track->mixerFlags));
g_mixer->playInputStream(track->getType(), &track->handle, track->stream, -1, track->getVol(), track->getPan());
g_mixer->pauseHandle(track->handle, true);
}
savedState->endSection();
g_mixer->pauseAll(false);
printf("Imuse::restoreState() finished.\n");
}
void Imuse::saveState(SaveGame *savedState) {
StackLock lock(_mutex);
Common::StackLock lock(_mutex);
printf("Imuse::saveState() started.\n");
savedState->beginSection('IMUS');
savedState->write(&_volVoice, sizeof(int32));
savedState->write(&_volSfx, sizeof(int32));
savedState->write(&_volMusic, sizeof(int32));
savedState->write(&_curMusicState, sizeof(int32));
savedState->write(&_curMusicSeq, sizeof(int32));
savedState->write(_attributes, sizeof(int32) * 185);
@ -174,31 +168,43 @@ void Imuse::saveState(SaveGame *savedState) {
savedState->write(track->soundName, 32);
savedState->write(&track->used, sizeof(bool));
savedState->write(&track->toBeRemoved, sizeof(bool));
savedState->write(&track->readyToRemove, sizeof(bool));
savedState->write(&track->started, sizeof(bool));
savedState->write(&track->priority, sizeof(int32));
savedState->write(&track->regionOffset, sizeof(int32));
savedState->write(&track->dataOffset, sizeof(int32));
savedState->write(&track->curRegion, sizeof(int32));
savedState->write(&track->curHookId, sizeof(int32));
savedState->write(&track->volGroupId, sizeof(int32));
savedState->write(&track->iteration, sizeof(int32));
savedState->write(&track->feedSize, sizeof(int32));
savedState->write(&track->mixerFlags, sizeof(int32));
savedState->write(&track->mixerVol, sizeof(int32));
savedState->write(&track->mixerPan, sizeof(int32));
}
savedState->endSection();
printf("Imuse::saveState() finished.\n");
}
int32 Imuse::makeMixerFlags(int32 flags) {
int32 mixerFlags = 0;
if (flags & kFlag16Bits)
mixerFlags |= Audio::Mixer::FLAG_16BITS;
if (flags & kFlagLittleEndian)
mixerFlags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
if (flags & kFlagStereo)
mixerFlags |= Audio::Mixer::FLAG_STEREO;
if (flags & kFlagReverseStereo)
mixerFlags |= Audio::Mixer::FLAG_REVERSE_STEREO;
return mixerFlags;
}
void Imuse::callback() {
StackLock lock(_mutex);
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->readyToRemove) {
if (track->toBeRemoved) {
track->readyToRemove = true;
if (track->used) {
// Ignore tracks which are about to finish. Also, if it did finish in the meantime,
// mark it as unused.
if (!track->stream) {
if (!g_mixer->isSoundHandleActive(track->handle))
memset(track, 0, sizeof(Track));
continue;
}
@ -209,17 +215,21 @@ void Imuse::callback() {
if (track->volFadeStep < 0) {
if (track->vol > track->volFadeDest) {
track->vol += track->volFadeStep;
//warning("fade: %d", track->vol);
if (track->vol < track->volFadeDest) {
track->vol = track->volFadeDest;
track->volFadeUsed = false;
}
if (track->vol == 0) {
track->toBeRemoved = true;
// Fade out complete -> remove this track
flushTrack(track);
continue;
}
}
} else if (track->volFadeStep > 0) {
if (track->vol < track->volFadeDest) {
track->vol += track->volFadeStep;
//warning("fade: %d", track->vol);
if (track->vol > track->volFadeDest) {
track->vol = track->volFadeDest;
track->volFadeUsed = false;
@ -248,74 +258,60 @@ void Imuse::callback() {
}
}
int pan = track->pan / 1000;
pan = (pan != 64) ? 2 * pan - 127 : 0;
int vol = track->vol / 1000;
assert(track->stream);
byte *data = NULL;
int32 result = 0;
if (track->volGroupId == 1)
vol = (vol * _volVoice) / 128;
if (track->volGroupId == 2)
vol = (vol * _volSfx) / 128;
if (track->volGroupId == 3)
vol = (vol * _volMusic) / 128;
track->mixerVol = vol;
track->mixerPan = pan;
if (track->stream) {
byte *data = NULL;
int32 result = 0;
if (track->curRegion == -1) {
switchToNextRegion(track);
if (track->toBeRemoved)
continue;
}
int channels = _sound->getChannels(track->soundHandle);
int32 mixer_size = track->iteration / _callbackFps;
if (track->stream->endOfData()) {
mixer_size *= 2;
}
if (channels == 1)
mixer_size &= ~1;
if (channels == 2)
mixer_size &= ~3;
if (mixer_size == 0)
if (track->curRegion == -1) {
switchToNextRegion(track);
if (!track->stream) // Seems we reached the end of the stream
continue;
}
do {
result = _sound->getDataFromRegion(track->soundHandle, track->curRegion, &data, track->regionOffset, mixer_size);
if (channels == 1) {
result &= ~1;
}
if (channels == 2) {
result &= ~3;
}
int channels = _sound->getChannels(track->soundDesc);
int32 mixer_size = track->feedSize / _callbackFps;
if (result > mixer_size)
result = mixer_size;
if (track->stream->endOfData()) {
mixer_size *= 2;
}
if (g_mixer->isReady()) {
g_mixer->setChannelVolume(track->handle, vol);
g_mixer->setChannelBalance(track->handle, pan);
track->stream->append(data, result);
track->regionOffset += result;
free(data);
}
if (channels == 1)
mixer_size &= ~1;
if (channels == 2)
mixer_size &= ~3;
if (_sound->isEndOfRegion(track->soundHandle, track->curRegion)) {
switchToNextRegion(track);
if (track->toBeRemoved)
break;
}
mixer_size -= result;
assert(mixer_size >= 0);
} while (mixer_size != 0);
if (mixer_size == 0)
continue;
do {
result = _sound->getDataFromRegion(track->soundDesc, track->curRegion, &data, track->regionOffset, mixer_size);
if (channels == 1) {
result &= ~1;
}
if (channels == 2) {
result &= ~3;
}
if (result > mixer_size)
result = mixer_size;
if (g_mixer->isReady()) {
track->stream->queueBuffer(data, result);
track->regionOffset += result;
} else
delete[] data;
if (_sound->isEndOfRegion(track->soundDesc, track->curRegion)) {
switchToNextRegion(track);
if (!track->stream)
break;
}
mixer_size -= result;
assert(mixer_size >= 0);
} while (mixer_size);
if (g_mixer->isReady()) {
g_mixer->setChannelVolume(track->handle, track->getVol());
g_mixer->setChannelBalance(track->handle, track->getPan());
}
}
}
@ -325,51 +321,51 @@ void Imuse::switchToNextRegion(Track *track) {
assert(track);
if (track->trackId >= MAX_IMUSE_TRACKS) {
track->toBeRemoved = true;
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::switchToNextRegion(): fadeTrack end: soundName:%s\n", track->soundName);
flushTrack(track);
return;
}
int numRegions = _sound->getNumRegions(track->soundHandle);
int numRegions = _sound->getNumRegions(track->soundDesc);
if (++track->curRegion == numRegions) {
track->toBeRemoved = true;
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::switchToNextRegion(): end of tracks: soundName:%s\n", track->soundName);
flushTrack(track);
return;
}
ImuseSndMgr::SoundStruct *soundHandle = track->soundHandle;
int jumpId = _sound->getJumpIdByRegionAndHookId(soundHandle, track->curRegion, track->curHookId);
ImuseSndMgr::SoundDesc *soundDesc = track->soundDesc;
int jumpId = _sound->getJumpIdByRegionAndHookId(soundDesc, track->curRegion, track->curHookId);
if (jumpId == -1)
jumpId = _sound->getJumpIdByRegionAndHookId(soundHandle, track->curRegion, 0);
jumpId = _sound->getJumpIdByRegionAndHookId(soundDesc, track->curRegion, 0);
if (jumpId != -1) {
int region = _sound->getRegionIdByJumpId(soundHandle, jumpId);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::switchToNextRegion(): JUMP: soundName:%s\n", track->soundName);
int region = _sound->getRegionIdByJumpId(soundDesc, jumpId);
assert(region != -1);
int sampleHookId = _sound->getJumpHookId(soundHandle, jumpId);
int sampleHookId = _sound->getJumpHookId(soundDesc, jumpId);
assert(sampleHookId != -1);
int fadeDelay = (60 * _sound->getJumpFade(soundHandle, jumpId)) / 1000;
if (sampleHookId != 0) {
if (track->curHookId == sampleHookId) {
if (fadeDelay != 0) {
Track *fadeTrack = cloneToFadeOutTrack(track, fadeDelay);
fadeTrack->dataOffset = _sound->getRegionOffset(fadeTrack->soundHandle, fadeTrack->curRegion);
fadeTrack->regionOffset = 0;
fadeTrack->curHookId = 0;
}
track->curRegion = region;
track->curHookId = 0;
}
} else {
if (fadeDelay != 0) {
Track *fadeTrack = cloneToFadeOutTrack(track, fadeDelay);
fadeTrack->dataOffset = _sound->getRegionOffset(fadeTrack->soundHandle, fadeTrack->curRegion);
int fadeDelay = (60 * _sound->getJumpFade(soundDesc, jumpId)) / 1000;
if (fadeDelay) {
Track *fadeTrack = cloneToFadeOutTrack(track, fadeDelay);
if (fadeTrack) {
fadeTrack->dataOffset = _sound->getRegionOffset(fadeTrack->soundDesc, fadeTrack->curRegion);
fadeTrack->regionOffset = 0;
}
track->curRegion = region;
if (track->curHookId == 0x80) {
track->curHookId = 0;
fadeTrack->curHookId = 0;
}
}
track->curRegion = region;
if (track->curHookId == sampleHookId)
track->curHookId = 0;
else
if (track->curHookId == 0x80)
track->curHookId = 0;
}
track->dataOffset = _sound->getRegionOffset(soundHandle, track->curRegion);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::switchToNextRegion(): REGION %d: soundName:%s\n", track->curRegion, track->soundName);
track->dataOffset = _sound->getRegionOffset(soundDesc, track->curRegion);
track->regionOffset = 0;
}

View File

@ -34,21 +34,12 @@
#include "engine/imuse/imuse_sndmgr.h"
#include "engine/imuse/imuse_mcmp_mgr.h"
#include "engine/imuse/imuse_track.h"
#include "engine/imuse/imuse_tables.h"
#define MAX_IMUSE_TRACKS 16
#define MAX_IMUSE_FADETRACKS 16
struct ImuseTable {
byte opcode;
int16 soundId;
byte atribPos;
byte hookId;
int16 fadeOut60TicksDelay;
byte volume;
byte pan;
char filename[32];
};
class SaveGame;
class Imuse {
@ -56,52 +47,11 @@ private:
int _callbackFps;
struct Track {
int trackId;
int32 pan;
int32 panFadeDest;
int32 panFadeStep;
int32 panFadeDelay;
bool panFadeUsed;
int32 vol;
int32 volFadeDest;
int32 volFadeStep;
int32 volFadeDelay;
bool volFadeUsed;
char soundName[32];
bool used;
bool toBeRemoved;
bool readyToRemove;
bool started;
int32 priority;
int32 regionOffset;
int32 dataOffset;
int32 curRegion;
int32 curHookId;
int32 volGroupId;
int32 iteration;
int32 mixerFlags;
int32 mixerVol;
int32 mixerPan;
ImuseSndMgr::SoundStruct *soundHandle;
PlayingSoundHandle handle;
AppendableAudioStream *stream;
Track();
};
Track *_track[MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS];
MutexRef _mutex;
Common::Mutex _mutex;
ImuseSndMgr *_sound;
int32 _volVoice;
int32 _volSfx;
int32 _volMusic;
bool _pause;
int32 _attributes[185];
@ -111,6 +61,7 @@ private:
const ImuseTable *_stateMusicTable;
const ImuseTable *_seqMusicTable;
int32 makeMixerFlags(int32 flags);
static void timerHandler(void *refConf);
void callback();
void switchToNextRegion(Track *track);
@ -118,30 +69,27 @@ private:
void selectVolumeGroup(const char *soundName, int volGroupId);
void fadeOutMusic(int fadeDelay);
void fadeOutMusicAndStartNew(int fadeDelay, const char *filename, int hookId, int vol, int pan);
Track *cloneToFadeOutTrack(Track *track, int fadeDelay);
void playMusic(const ImuseTable *table, int atribPos, bool sequence);
void flushTrack(Track *track);
public:
Imuse(int fps);
~Imuse();
bool startSound(const char *soundName, int volGroupId, int hookId, int volume, int pan, int priority);
bool startSound(const char *soundName, int volGroupId, int hookId, int volume, int pan, int priority, Track *otherTrack);
void startVoice(const char *soundName, int volume = 127, int pan = 64);
void startMusic(const char *soundName, int hookId, int volume, int pan);
void startMusicWithOtherPos(const char *soundName, int hookId, int volume, int pan, Track *otherTrack);
void startSfx(const char *soundName, int priority = 127);
void restoreState(SaveGame *savedState);
void saveState(SaveGame *savedState);
void resetState();
void setGroupVoiceVolume(int volume) { _volVoice = volume; }
void setGroupSfxVolume(int volume) { _volSfx = volume; }
void setGroupMusicVolume(int volume) { _volMusic = volume; }
int getGroupVoiceVolume() { return _volVoice; }
int getGroupSfxVolume() { return _volSfx; }
int getGroupMusicVolume() { return _volMusic; }
Track *findTrack(const char *soundName);
void setPriority(const char *soundName, int priority);
void setVolume(const char *soundName, int volume);
@ -160,6 +108,8 @@ public:
void flushTracks();
bool isVoicePlaying();
char *getCurMusicSoundName();
int getCurMusicPan();
int getCurMusicVol();
bool getSoundStatus(const char *soundName);
int32 getPosIn60HzTicks(const char *soundName);
};

View File

@ -45,10 +45,8 @@ McmpMgr::McmpMgr() {
McmpMgr::~McmpMgr() {
if (_file)
fclose(_file);
if (_compTable)
free(_compTable);
if (_compInput)
free(_compInput);
delete[] _compTable;
delete[] _compInput;
}
bool McmpMgr::openSound(const char *filename, byte **resPtr, int &offsetData) {
@ -72,7 +70,7 @@ bool McmpMgr::openSound(const char *filename, byte **resPtr, int &offsetData) {
int offset = ftell(_file) + (_numCompItems * 9) + 2;
_numCompItems--;
_compTable = (CompTable *)malloc(sizeof(CompTable) * _numCompItems);
_compTable = new CompTable[_numCompItems];
fseek(_file, 5, SEEK_CUR);
fread(&_compTable[0].decompSize, 1, 4, _file);
int headerSize = _compTable[0].decompSize = READ_BE_UINT32(&_compTable[0].decompSize);
@ -98,7 +96,7 @@ bool McmpMgr::openSound(const char *filename, byte **resPtr, int &offsetData) {
_compTable[i].offset += sizeCodecs;
}
fseek(_file, sizeCodecs, SEEK_CUR);
_compInput = (byte *)malloc(maxSize);
_compInput = new byte[maxSize];
fread(_compInput, 1, headerSize, _file);
*resPtr = _compInput;
offsetData = headerSize;
@ -123,7 +121,7 @@ int32 McmpMgr::decompressSample(int32 offset, int32 size, byte **comp_final) {
last_block = _numCompItems - 1;
int32 blocks_final_size = 0x2000 * (1 + last_block - first_block);
*comp_final = (byte *)malloc(blocks_final_size);
*comp_final = new byte[blocks_final_size];
final_size = 0;
for (i = first_block; i <= last_block; i++) {

View File

@ -40,10 +40,13 @@ void Imuse::setMusicState(int stateId) {
}
assert(num != -1);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::setMusicState(): SoundId %d, filename: %s\n", _stateMusicTable[l].soundId, _stateMusicTable[l].filename);
if (_curMusicState == num)
return;
if (_curMusicSeq == 0) {
if (!_curMusicSeq) {
playMusic(&_stateMusicTable[num], num, false);
}
@ -68,10 +71,13 @@ int Imuse::setMusicSequence(int seqId) {
assert(num != -1);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::setMusicSequence(): SoundId %d, filename: %s\n", _seqMusicTable[l].soundId, _seqMusicTable[l].filename);
if (_curMusicSeq == num)
return _seqMusicTable[_curMusicSeq].soundId;
if (num != 0) {
if (num) {
playMusic(&_seqMusicTable[num], 0, true);
} else {
playMusic(&_stateMusicTable[_curMusicState], _curMusicState, true);
@ -85,12 +91,12 @@ int Imuse::setMusicSequence(int seqId) {
void Imuse::playMusic(const ImuseTable *table, int atribPos, bool sequence) {
int hookId = 0;
if (atribPos != 0) {
if (table->atribPos != 0)
if (atribPos) {
if (table->atribPos)
atribPos = table->atribPos;
hookId = _attributes[atribPos];
if (table->hookId != 0) {
if ((hookId == 0) && (table->hookId > 1)) {
if (table->hookId) {
if (hookId && table->hookId > 1) {
_attributes[atribPos] = 2;
} else {
_attributes[atribPos] = hookId + 1;
@ -104,27 +110,51 @@ void Imuse::playMusic(const ImuseTable *table, int atribPos, bool sequence) {
if (table->opcode == 0) {
fadeOutMusic(120);
} else if ((table->opcode == 2) || (table->opcode == 3)) {
return;
}
if (table->opcode == 2 || table->opcode == 3) {
if (table->filename[0] == 0) {
fadeOutMusic(60);
} else {
char *soundName = getCurMusicSoundName();
int pan;
return;
}
char *soundName = getCurMusicSoundName();
int pan;
if (table->pan == 0)
pan = 64;
else
pan = table->pan;
if (soundName != NULL && (table->opcode == 3) && (!sequence)
&& (strcmp(soundName, table->filename) == 0) && (table->atribPos != 0)
&& table->atribPos == _stateMusicTable[_curMusicState].atribPos) {
setFadeVolume(soundName, table->volume, table->fadeOut60TicksDelay);
setFadePan(soundName, pan, table->fadeOut60TicksDelay);
setHookId(soundName, hookId);
} else {
fadeOutMusic(table->fadeOut60TicksDelay);
startMusic(table->filename, hookId, table->volume, pan);
}
if (table->pan == 0)
pan = 64;
else
pan = table->pan;
if (!soundName) {
startMusic(table->filename, hookId, 0, pan);
setFadeVolume(table->filename, table->volume, table->fadeOut60TicksDelay);
return;
}
int old_pan = getCurMusicPan();
int old_vol = getCurMusicVol();
if (old_pan == -1)
old_pan = 64;
if (old_vol == -1)
old_vol = 127;
if (table->opcode == 2) {
fadeOutMusic(table->fadeOut60TicksDelay);
startMusic(table->filename, hookId, table->volume, pan);
return;
}
if (strcmp(soundName, table->filename) == 0) {
setFadeVolume(soundName, table->volume, table->fadeOut60TicksDelay);
setFadePan(soundName, pan, table->fadeOut60TicksDelay);
return;
}
if (!sequence && table->atribPos && table->atribPos == _stateMusicTable[_curMusicState].atribPos) {
fadeOutMusicAndStartNew(table->fadeOut60TicksDelay, table->filename, hookId, old_vol, old_pan);
setFadeVolume(table->filename, table->volume, table->fadeOut60TicksDelay);
setFadePan(table->filename, pan, table->fadeOut60TicksDelay);
} else {
fadeOutMusic(table->fadeOut60TicksDelay);
startMusic(table->filename, hookId, table->volume, pan);
}
}
}

View File

@ -24,6 +24,7 @@
#include "common/platform.h"
#include "common/debug.h"
#include "common/timer.h"
#include "common/mutex.h"
#include "engine/backend/driver.h"
@ -33,34 +34,41 @@
#include "engine/imuse/imuse.h"
#include "engine/imuse/imuse_sndmgr.h"
void Imuse::flushTrack(Track *track) {
track->toBeRemoved = true;
if (track->stream) {
// Finalize the appendable stream, then remove our reference to it.
// Note that there might still be some data left in the buffers of the
// appendable stream. We play it nice and wait till all of it
// played. The audio mixer will take care of it afterwards (and dispose it).
track->stream->finish();
track->stream = 0;
if (track->soundDesc) {
_sound->closeSound(track->soundDesc);
track->soundDesc = 0;
}
}
if (!g_mixer->isSoundHandleActive(track->handle)) {
memset(track, 0, sizeof(Track));
}
}
void Imuse::flushTracks() {
// flushTracks should not lock the stack since all the functions
// that call it already do (stopAllSounds, startSound)
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
Track *track = _track[l];
if (track->used && track->readyToRemove) {
if (track->stream) {
if (!track->stream->endOfStream()) {
track->stream->finish();
}
if (track->stream->endOfStream()) {
g_mixer->stopHandle(track->handle);
delete track->stream;
track->stream = NULL;
_sound->closeSound(track->soundHandle);
track->soundHandle = NULL;
track->used = false;
strcpy(track->soundName, "");
}
}
if (track->used && track->toBeRemoved && !g_mixer->isSoundHandleActive(track->handle)) {
memset(track, 0, sizeof(Track));
}
}
}
void Imuse::refreshScripts() {
Common::StackLock lock(_mutex);
bool found = false;
StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
@ -68,52 +76,58 @@ void Imuse::refreshScripts() {
}
}
if (!found && (_curMusicSeq != 0)) {
setMusicSequence(2000);
if (!found && _curMusicState) {
setMusicSequence(0);
}
}
void Imuse::startVoice(const char *soundName, int volume, int pan) {
startSound(soundName, IMUSE_VOLGRP_VOICE, 0, volume, pan, 127);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::startVoice(): SoundName %s, vol:%d, pan:%d\n", soundName, volume, pan);
startSound(soundName, IMUSE_VOLGRP_VOICE, 0, volume, pan, 127, NULL);
}
void Imuse::startMusic(const char *soundName, int hookId, int volume, int pan) {
startSound(soundName, IMUSE_VOLGRP_MUSIC, hookId, volume, pan, 126);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::startMusic(): SoundName %s, hookId:%d, vol:%d, pan:%d\n", soundName, hookId, volume, pan);
startSound(soundName, IMUSE_VOLGRP_MUSIC, hookId, volume, pan, 126, NULL);
}
void Imuse::startMusicWithOtherPos(const char *soundName, int hookId, int volume, int pan, Track *otherTrack) {
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::startMusicWithOtherPos(): SoundName %s, hookId:%d, vol:%d, pan:%d\n", soundName, volume, pan);
startSound(soundName, IMUSE_VOLGRP_MUSIC, hookId, volume, pan, 126, otherTrack);
}
void Imuse::startSfx(const char *soundName, int priority) {
startSound(soundName, IMUSE_VOLGRP_SFX, 0, 127, 0, priority);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::startSfx(): SoundName %s, priority:%d\n", soundName, priority);
startSound(soundName, IMUSE_VOLGRP_SFX, 0, 127, 0, priority, NULL);
}
int32 Imuse::getPosIn60HzTicks(const char *soundName) {
Common::StackLock lock(_mutex);
Track *getTrack = NULL;
getTrack = findTrack(soundName);
// Warn the user if the track was not found
if (getTrack == NULL) {
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
warning("Music track '%s' could not be found to get ticks!", soundName);
warning("Sound '%s' could not be found to get ticks!", soundName);
return false;
}
if (getTrack->handle.isActive()) {
int32 pos = (5 * (getTrack->dataOffset + getTrack->regionOffset)) / (getTrack->iteration / 12);
return pos;
}
return -1;
int32 pos = (5 * (getTrack->dataOffset + getTrack->regionOffset)) / (getTrack->feedSize / 200);
return pos;
}
bool Imuse::isVoicePlaying() {
StackLock lock(_mutex);
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
// Make sure the track is in use before checking the group ID,
// otherwise volGroupId can be uninitialized or reference an
// old track.
if (track->used && track->volGroupId == IMUSE_VOLGRP_VOICE) {
if (track->handle.isActive()) {
if (g_mixer->isSoundHandleActive(track->handle))
return true;
}
}
}
@ -121,51 +135,55 @@ bool Imuse::isVoicePlaying() {
}
bool Imuse::getSoundStatus(const char *soundName) {
Track *statusTrack = NULL;
Common::StackLock lock(_mutex);
Track *track = NULL;
// If there's no name then don't try to get the status!
if (strlen(soundName) == 0)
return false;
statusTrack = findTrack(soundName);
track = findTrack(soundName);
// Warn the user if the track was not found
if (statusTrack == NULL) {
if (track == NULL || !g_mixer->isSoundHandleActive(track->handle)) {
// This debug warning should be "light" since this function gets called
// on occassion to see if a sound has stopped yet
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
printf("Music track '%s' could not be found to get status, assume inactive.\n", soundName);
printf("Sound '%s' could not be found to get status, assume inactive.\n", soundName);
return false;
}
return statusTrack->handle.isActive();
return true;
}
void Imuse::stopSound(const char *soundName) {
Common::StackLock lock(_mutex);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::stopSound(): SoundName %s\n", soundName);
Track *removeTrack = NULL;
removeTrack = findTrack(soundName);
// Warn the user if the track was not found
if (removeTrack == NULL) {
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
warning("Music track '%s' could not be found to stop!", soundName);
warning("Sound track '%s' could not be found to stop!", soundName);
return;
}
removeTrack->toBeRemoved = true;
flushTrack(removeTrack);
}
void Imuse::stopAllSounds() {
for (;;) {
bool foundNotRemoved = false;
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
Track *track = _track[l];
if (track->used) {
track->toBeRemoved = true;
foundNotRemoved = true;
Common::StackLock lock(_mutex);
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ALL)
printf("Imuse::stopAllSounds()\n");
for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
Track *track = _track[l];
if (track->used) {
g_mixer->stopHandle(track->handle);
if (track->soundDesc) {
_sound->closeSound(track->soundDesc);
}
memset(track, 0, sizeof(Track));
}
if (!foundNotRemoved)
break;
flushTracks();
g_driver->delayMillis(50);
}
}

View File

@ -35,7 +35,7 @@
ImuseSndMgr::ImuseSndMgr() {
for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
memset(&_sounds[l], 0, sizeof(SoundStruct));
memset(&_sounds[l], 0, sizeof(SoundDesc));
}
}
@ -72,10 +72,10 @@ void ImuseSndMgr::countElements(byte *ptr, int &numRegions, int &numJumps) {
} while (tag != MKID_BE('DATA'));
}
void ImuseSndMgr::parseSoundHeader(byte *ptr, SoundStruct *sound, int &headerSize) {
void ImuseSndMgr::parseSoundHeader(byte *ptr, SoundDesc *sound, int &headerSize) {
if (READ_UINT32(ptr) == MKID('RIFF')) {
sound->region = (Region *)malloc(sizeof(Region));
sound->jump = (Jump *)malloc(0);
sound->region = new Region[1];
sound->jump = new Jump[0];
sound->numJumps = 0;
sound->numRegions = 1;
sound->region[0].offset = 0;
@ -96,8 +96,8 @@ void ImuseSndMgr::parseSoundHeader(byte *ptr, SoundStruct *sound, int &headerSiz
sound->numRegions = 0;
sound->numJumps = 0;
countElements(ptr, sound->numRegions, sound->numJumps);
sound->region = (Region *)malloc(sizeof(Region) * sound->numRegions);
sound->jump = (Jump *)malloc(sizeof(Jump) * sound->numJumps);
sound->region = new Region [sound->numRegions];
sound->jump = new Jump [sound->numJumps];
do {
tag = READ_BE_UINT32(ptr); ptr += 4;
@ -147,7 +147,7 @@ void ImuseSndMgr::parseSoundHeader(byte *ptr, SoundStruct *sound, int &headerSiz
}
}
ImuseSndMgr::SoundStruct *ImuseSndMgr::allocSlot() {
ImuseSndMgr::SoundDesc *ImuseSndMgr::allocSlot() {
for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
if (!_sounds[l].inUse) {
_sounds[l].inUse = true;
@ -158,12 +158,12 @@ ImuseSndMgr::SoundStruct *ImuseSndMgr::allocSlot() {
return NULL;
}
ImuseSndMgr::SoundStruct *ImuseSndMgr::openSound(const char *soundName, int volGroupId) {
ImuseSndMgr::SoundDesc *ImuseSndMgr::openSound(const char *soundName, int volGroupId) {
const char *extension = soundName + std::strlen(soundName) - 3;
byte *ptr = NULL;
int headerSize = 0;
SoundStruct *sound = allocSlot();
SoundDesc *sound = allocSlot();
if (!sound) {
error("ImuseSndMgr::openSound() Can't alloc free sound slot");
}
@ -197,94 +197,94 @@ ImuseSndMgr::SoundStruct *ImuseSndMgr::openSound(const char *soundName, int volG
return sound;
}
void ImuseSndMgr::closeSound(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
void ImuseSndMgr::closeSound(SoundDesc *sound) {
assert(checkForProperHandle(sound));
if (soundHandle->mcmpMgr) {
delete soundHandle->mcmpMgr;
soundHandle->mcmpMgr = NULL;
if (sound->mcmpMgr) {
delete sound->mcmpMgr;
sound->mcmpMgr = NULL;
}
if (soundHandle->blockRes) {
delete soundHandle->blockRes;
soundHandle->blockRes = NULL;
if (sound->blockRes) {
delete sound->blockRes;
sound->blockRes = NULL;
}
if (soundHandle->region) {
free(soundHandle->region);
soundHandle->region = NULL;
if (sound->region) {
delete[] sound->region;
sound->region = NULL;
}
if (soundHandle->jump) {
free(soundHandle->jump);
soundHandle->jump = NULL;
if (sound->jump) {
delete[] sound->jump;
sound->jump = NULL;
}
memset(soundHandle, 0, sizeof(SoundStruct));
memset(sound, 0, sizeof(SoundDesc));
}
ImuseSndMgr::SoundStruct *ImuseSndMgr::cloneSound(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
ImuseSndMgr::SoundDesc *ImuseSndMgr::cloneSound(SoundDesc *sound) {
assert(checkForProperHandle(sound));
return openSound(soundHandle->name, soundHandle->volGroupId);
return openSound(sound->name, sound->volGroupId);
}
bool ImuseSndMgr::checkForProperHandle(SoundStruct *soundHandle) {
if (!soundHandle)
bool ImuseSndMgr::checkForProperHandle(SoundDesc *sound) {
if (!sound)
return false;
for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
if (soundHandle == &_sounds[l])
if (sound == &_sounds[l])
return true;
}
return false;
}
int ImuseSndMgr::getFreq(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
return soundHandle->freq;
int ImuseSndMgr::getFreq(SoundDesc *sound) {
assert(checkForProperHandle(sound));
return sound->freq;
}
int ImuseSndMgr::getBits(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
return soundHandle->bits;
int ImuseSndMgr::getBits(SoundDesc *sound) {
assert(checkForProperHandle(sound));
return sound->bits;
}
int ImuseSndMgr::getChannels(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
return soundHandle->channels;
int ImuseSndMgr::getChannels(SoundDesc *sound) {
assert(checkForProperHandle(sound));
return sound->channels;
}
bool ImuseSndMgr::isEndOfRegion(SoundStruct *soundHandle, int region) {
assert(checkForProperHandle(soundHandle));
assert(region >= 0 && region < soundHandle->numRegions);
return soundHandle->endFlag;
bool ImuseSndMgr::isEndOfRegion(SoundDesc *sound, int region) {
assert(checkForProperHandle(sound));
assert(region >= 0 && region < sound->numRegions);
return sound->endFlag;
}
int ImuseSndMgr::getNumRegions(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
return soundHandle->numRegions;
int ImuseSndMgr::getNumRegions(SoundDesc *sound) {
assert(checkForProperHandle(sound));
return sound->numRegions;
}
int ImuseSndMgr::getNumJumps(SoundStruct *soundHandle) {
assert(checkForProperHandle(soundHandle));
return soundHandle->numJumps;
int ImuseSndMgr::getNumJumps(SoundDesc *sound) {
assert(checkForProperHandle(sound));
return sound->numJumps;
}
int ImuseSndMgr::getRegionOffset(SoundStruct *soundHandle, int region) {
assert(checkForProperHandle(soundHandle));
assert(region >= 0 && region < soundHandle->numRegions);
return soundHandle->region[region].offset;
int ImuseSndMgr::getRegionOffset(SoundDesc *sound, int region) {
assert(checkForProperHandle(sound));
assert(region >= 0 && region < sound->numRegions);
return sound->region[region].offset;
}
int ImuseSndMgr::getJumpIdByRegionAndHookId(SoundStruct *soundHandle, int region, int hookId) {
assert(checkForProperHandle(soundHandle));
assert(region >= 0 && region < soundHandle->numRegions);
int32 offset = soundHandle->region[region].offset;
for (int l = 0; l < soundHandle->numJumps; l++) {
if (offset == soundHandle->jump[l].offset) {
if (soundHandle->jump[l].hookId == hookId)
int ImuseSndMgr::getJumpIdByRegionAndHookId(SoundDesc *sound, int region, int hookId) {
assert(checkForProperHandle(sound));
assert(region >= 0 && region < sound->numRegions);
int32 offset = sound->region[region].offset;
for (int l = 0; l < sound->numJumps; l++) {
if (offset == sound->jump[l].offset) {
if (sound->jump[l].hookId == hookId)
return l;
}
}
@ -292,12 +292,12 @@ int ImuseSndMgr::getJumpIdByRegionAndHookId(SoundStruct *soundHandle, int region
return -1;
}
int ImuseSndMgr::getRegionIdByJumpId(SoundStruct *soundHandle, int jumpId) {
assert(checkForProperHandle(soundHandle));
assert(jumpId >= 0 && jumpId < soundHandle->numJumps);
int32 dest = soundHandle->jump[jumpId].dest;
for (int l = 0; l < soundHandle->numRegions; l++) {
if (dest == soundHandle->region[l].offset) {
int ImuseSndMgr::getRegionIdByJumpId(SoundDesc *sound, int jumpId) {
assert(checkForProperHandle(sound));
assert(jumpId >= 0 && jumpId < sound->numJumps);
int32 dest = sound->jump[jumpId].dest;
for (int l = 0; l < sound->numRegions; l++) {
if (dest == sound->region[l].offset) {
return l;
}
}
@ -305,38 +305,38 @@ int ImuseSndMgr::getRegionIdByJumpId(SoundStruct *soundHandle, int jumpId) {
return -1;
}
int ImuseSndMgr::getJumpHookId(SoundStruct *soundHandle, int number) {
assert(checkForProperHandle(soundHandle));
assert(number >= 0 && number < soundHandle->numJumps);
return soundHandle->jump[number].hookId;
int ImuseSndMgr::getJumpHookId(SoundDesc *sound, int number) {
assert(checkForProperHandle(sound));
assert(number >= 0 && number < sound->numJumps);
return sound->jump[number].hookId;
}
int ImuseSndMgr::getJumpFade(SoundStruct *soundHandle, int number) {
assert(checkForProperHandle(soundHandle));
assert(number >= 0 && number < soundHandle->numJumps);
return soundHandle->jump[number].fadeDelay;
int ImuseSndMgr::getJumpFade(SoundDesc *sound, int number) {
assert(checkForProperHandle(sound));
assert(number >= 0 && number < sound->numJumps);
return sound->jump[number].fadeDelay;
}
int32 ImuseSndMgr::getDataFromRegion(SoundStruct *soundHandle, int region, byte **buf, int32 offset, int32 size) {
assert(checkForProperHandle(soundHandle));
int32 ImuseSndMgr::getDataFromRegion(SoundDesc *sound, int region, byte **buf, int32 offset, int32 size) {
assert(checkForProperHandle(sound));
assert(buf && offset >= 0 && size >= 0);
assert(region >= 0 && region < soundHandle->numRegions);
assert(region >= 0 && region < sound->numRegions);
int32 region_offset = soundHandle->region[region].offset;
int32 region_length = soundHandle->region[region].length;
int32 region_offset = sound->region[region].offset;
int32 region_length = sound->region[region].length;
if (offset + size > region_length) {
size = region_length - offset;
soundHandle->endFlag = true;
sound->endFlag = true;
} else {
soundHandle->endFlag = false;
sound->endFlag = false;
}
if (soundHandle->mcmpData) {
size = soundHandle->mcmpMgr->decompressSample(region_offset + offset, size, buf);
if (sound->mcmpData) {
size = sound->mcmpMgr->decompressSample(region_offset + offset, size, buf);
} else {
*buf = (byte *)malloc(size);
memcpy(*buf, soundHandle->resPtr + region_offset + offset, size);
*buf = new byte[size];
memcpy(*buf, sound->resPtr + region_offset + offset, size);
}
return size;

View File

@ -64,7 +64,7 @@ private:
public:
struct SoundStruct {
struct SoundDesc {
uint16 freq; // frequency
byte channels; // stereo or mono
byte bits; // 8, 12, 16
@ -77,6 +77,7 @@ public:
char name[32];
McmpMgr *mcmpMgr;
Block *blockRes;
int type;
int volGroupId;
byte *resPtr;
bool mcmpData;
@ -84,11 +85,11 @@ public:
private:
SoundStruct _sounds[MAX_IMUSE_SOUNDS];
SoundDesc _sounds[MAX_IMUSE_SOUNDS];
bool checkForProperHandle(SoundStruct *soundHandle);
SoundStruct *allocSlot();
void parseSoundHeader(byte *ptr, SoundStruct *sound, int &headerSize);
bool checkForProperHandle(SoundDesc *soundDesc);
SoundDesc *allocSlot();
void parseSoundHeader(byte *ptr, SoundDesc *sound, int &headerSize);
void countElements(byte *ptr, int &numRegions, int &numJumps);
public:
@ -96,23 +97,23 @@ public:
ImuseSndMgr();
~ImuseSndMgr();
SoundStruct *openSound(const char *soundName, int volGroupId);
void closeSound(SoundStruct *soundHandle);
SoundStruct *cloneSound(SoundStruct *soundHandle);
SoundDesc *openSound(const char *soundName, int volGroupId);
void closeSound(SoundDesc *sound);
SoundDesc *cloneSound(SoundDesc *sound);
int getFreq(SoundStruct *soundHandle);
int getBits(SoundStruct *soundHandle);
int getChannels(SoundStruct *soundHandle);
bool isEndOfRegion(SoundStruct *soundHandle, int region);
int getNumRegions(SoundStruct *soundHandle);
int getNumJumps(SoundStruct *soundHandle);
int getRegionOffset(SoundStruct *soundHandle, int region);
int getJumpIdByRegionAndHookId(SoundStruct *soundHandle, int region, int hookId);
int getRegionIdByJumpId(SoundStruct *soundHandle, int jumpId);
int getJumpHookId(SoundStruct *soundHandle, int number);
int getJumpFade(SoundStruct *soundHandle, int number);
int getFreq(SoundDesc *sound);
int getBits(SoundDesc *sound);
int getChannels(SoundDesc *sound);
bool isEndOfRegion(SoundDesc *sound, int region);
int getNumRegions(SoundDesc *sound);
int getNumJumps(SoundDesc *sound);
int getRegionOffset(SoundDesc *sound, int region);
int getJumpIdByRegionAndHookId(SoundDesc *sound, int region, int hookId);
int getRegionIdByJumpId(SoundDesc *sound, int jumpId);
int getJumpHookId(SoundDesc *sound, int number);
int getJumpFade(SoundDesc *sound, int number);
int32 getDataFromRegion(SoundStruct *soundHandle, int region, byte **buf, int32 offset, int32 size);
int32 getDataFromRegion(SoundDesc *sound, int region, byte **buf, int32 offset, int32 size);
};
#endif

View File

@ -0,0 +1,49 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* $URL$
* $Id$
*
*/
#ifndef IMUSE_TABLES_H
#define IMUSE_TABLES_H
#include "common/sys.h"
#include "common/platform.h"
#include "common/debug.h"
#include "engine/lua.h"
#include "mixer/mixer.h"
#include "mixer/audiostream.h"
#include "engine/imuse/imuse_sndmgr.h"
#include "engine/imuse/imuse_mcmp_mgr.h"
struct ImuseTable {
byte opcode;
int16 soundId;
byte atribPos;
byte hookId;
int16 fadeOut60TicksDelay;
byte volume;
byte pan;
char filename[32];
};
#endif

View File

@ -23,6 +23,7 @@
#include "common/sys.h"
#include "common/platform.h"
#include "common/debug.h"
#include "common/mutex.h"
#include "engine/backend/driver.h"
@ -31,6 +32,7 @@
#include "engine/imuse/imuse.h"
#include "engine/imuse/imuse_sndmgr.h"
#include "engine/imuse/imuse_track.h"
int Imuse::allocSlot(int priority) {
int l, lowest_priority = 127;
@ -39,35 +41,46 @@ int Imuse::allocSlot(int priority) {
// allocSlot called by startSound so no locking is necessary
for (l = 0; l < MAX_IMUSE_TRACKS; l++) {
if (!_track[l]->used) {
return l; // Found an unused track
trackId = l;
break;
}
}
warning("Imuse::startSound(): All slots are full");
for (l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && lowest_priority > track->priority) {
lowest_priority = track->priority;
trackId = l;
if (trackId == -1) {
warning("Imuse::startSound(): All slots are full");
for (l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved &&
(lowest_priority > track->priority)) {
lowest_priority = track->priority;
trackId = l;
}
}
if (lowest_priority <= priority) {
assert(trackId != -1);
Track *track = _track[trackId];
// Stop the track immediately
g_mixer->stopHandle(track->handle);
if (track->soundDesc) {
_sound->closeSound(track->soundDesc);
}
// Mark it as unused
memset(track, 0, sizeof(Track));
} else {
return -1;
}
}
if (lowest_priority <= priority) {
assert(trackId != -1);
_track[trackId]->toBeRemoved = true;
warning("Imuse::startSound(): Removed sound %s from track %d", _track[trackId]->soundName, trackId);
} else {
warning("Imuse::startSound(): Priority sound too low");
return -1;
}
return trackId;
}
bool Imuse::startSound(const char *soundName, int volGroupId, int hookId, int volume, int pan, int priority) {
bool Imuse::startSound(const char *soundName, int volGroupId, int hookId, int volume, int pan, int priority, Track *otherTrack) {
Common::StackLock lock(_mutex);
Track *track = NULL;
int i, l = -1;
StackLock lock(_mutex);
int i;
// If the track is already playing then there is absolutely no
// reason to start it again, the existing track should be modified
// instead of starting a new copy of the track
@ -79,111 +92,73 @@ bool Imuse::startSound(const char *soundName, int volGroupId, int hookId, int vo
return true;
}
}
// Priority Level 127 appears to mean "load but don't play", so
// within our paradigm this is a much lower priority than everything
// else we're doing
if (priority == 127)
priority = -1;
l = allocSlot(priority);
int l = allocSlot(priority);
if (l == -1) {
warning("Imuse::startSound(): Can't start sound - no free slots");
return false;
}
track = _track[l];
i = 5;
// At this time it is inappropriate to assume that this will always
// succeed, so set a limit of 5 tries on running flushTracks
while (track->used && i > 0) {
// The designated track is not yet available. So, we call flushTracks()
// to get it processed (and thus made ready for us). Since the actual
// processing is done by another thread, we also call parseEvents to
// give it some time (and to avoid busy waiting/looping).
flushTracks();
i--;
}
if (i == 0) {
if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
warning("Imuse::startSound(): flushTracks was unable to free up a track for %s!", soundName);
warning("Imuse::startSound() Can't start sound - no free slots");
return false;
}
track = _track[l];
// Reset the track
memset(track, 0, sizeof(Track));
track->pan = pan * 1000;
track->panFadeDest = 0;
track->panFadeStep = 0;
track->panFadeDelay = 0;
track->panFadeUsed = false;
track->vol = volume * 1000;
track->volFadeDest = 0;
track->volFadeStep = 0;
track->volFadeDelay = 0;
track->volFadeUsed = false;
track->started = false;
track->volGroupId = volGroupId;
track->curHookId = hookId;
track->priority = priority;
track->curRegion = -1;
track->dataOffset = 0;
track->regionOffset = 0;
track->mixerFlags = 0;
track->mixerPan = 0;
track->mixerVol = volume;
track->toBeRemoved = false;
track->readyToRemove = false;
int bits = 0, freq = 0, channels = 0;
strcpy(track->soundName, soundName);
track->soundHandle = _sound->openSound(soundName, volGroupId);
track->soundDesc = _sound->openSound(soundName, volGroupId);
if (track->soundHandle == NULL)
if (!track->soundDesc)
return false;
bits = _sound->getBits(track->soundHandle);
channels = _sound->getChannels(track->soundHandle);
freq = _sound->getFreq(track->soundHandle);
bits = _sound->getBits(track->soundDesc);
channels = _sound->getChannels(track->soundDesc);
freq = _sound->getFreq(track->soundDesc);
assert(bits == 8 || bits == 12 || bits == 16);
assert(channels == 1 || channels == 2);
assert(0 < freq && freq <= 65535);
track->iteration = freq * channels * 2;
track->mixerFlags = SoundMixer::FLAG_16BITS;
track->feedSize = freq * channels * 2;
track->mixerFlags = kFlag16Bits;
if (channels == 2)
track->mixerFlags |= SoundMixer::FLAG_STEREO | SoundMixer::FLAG_REVERSE_STEREO;
track->mixerFlags |= kFlagStereo | kFlagReverseStereo;
pan = track->pan / 1000;
pan = (pan != 64) ? 2 * pan - 127 : 0;
volume = track->vol / 1000;
if (otherTrack && otherTrack->used && !otherTrack->toBeRemoved) {
track->curRegion = otherTrack->curRegion;
track->dataOffset = otherTrack->dataOffset;
track->regionOffset = otherTrack->regionOffset;
}
if (track->volGroupId == 1)
volume = (volume * _volVoice) / 128;
if (track->volGroupId == 2)
volume = (volume * _volSfx) / 128;
if (track->volGroupId == 3)
volume = (volume * _volMusic) / 128;
track->mixerPan = pan;
track->mixerVol = volume;
// setup 1 second stream wrapped buffer
int32 streamBufferSize = track->iteration;
track->stream = makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
g_mixer->playInputStream(&track->handle, track->stream, false, -1, track->mixerVol, track->mixerPan, false);
track->started = true;
track->stream = Audio::makeAppendableAudioStream(freq, makeMixerFlags(track->mixerFlags));
g_mixer->playInputStream(track->getType(), &track->handle, track->stream, -1, track->getVol(), track->getPan());
track->used = true;
return true;
}
Imuse::Track *Imuse::findTrack(const char *soundName) {
StackLock lock(_mutex);
Track *Imuse::findTrack(const char *soundName) {
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
// Since the audio (at least for Eva's keystrokes) can be referenced
// two ways: keyboard.IMU and keyboard.imu, make a case insensitive
// search for the track to make sure we can find it
if (strlen(track->soundName) != 0 && strcasecmp(track->soundName, soundName) == 0) {
if (track->used && !track->toBeRemoved
&& strlen(track->soundName) != 0 && strcasecmp(track->soundName, soundName) == 0) {
return track;
}
}
@ -191,6 +166,7 @@ Imuse::Track *Imuse::findTrack(const char *soundName) {
}
void Imuse::setPriority(const char *soundName, int priority) {
Common::StackLock lock(_mutex);
Track *changeTrack = NULL;
assert ((priority >= 0) && (priority <= 127));
@ -204,6 +180,7 @@ void Imuse::setPriority(const char *soundName, int priority) {
}
void Imuse::setVolume(const char *soundName, int volume) {
Common::StackLock lock(_mutex);
Track *changeTrack;
changeTrack = findTrack(soundName);
@ -215,17 +192,19 @@ void Imuse::setVolume(const char *soundName, int volume) {
}
void Imuse::setPan(const char *soundName, int pan) {
Common::StackLock lock(_mutex);
Track *changeTrack;
changeTrack = findTrack(soundName);
if (changeTrack == NULL) {
warning("Unable to find track '%s' to change volume!", soundName);
warning("Unable to find track '%s' to change pan!", soundName);
return;
}
changeTrack->pan = pan;
changeTrack->pan = pan * 1000;
}
int Imuse::getVolume(const char *soundName) {
Common::StackLock lock(_mutex);
Track *getTrack;
getTrack = findTrack(soundName);
@ -237,6 +216,7 @@ int Imuse::getVolume(const char *soundName) {
}
void Imuse::setHookId(const char *soundName, int hookId) {
Common::StackLock lock(_mutex);
Track *changeTrack;
changeTrack = findTrack(soundName);
@ -248,12 +228,12 @@ void Imuse::setHookId(const char *soundName, int hookId) {
}
int Imuse::getCountPlayedTracks(const char *soundName) {
Common::StackLock lock(_mutex);
int count = 0;
StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (strcmp(track->soundName, soundName) == 0)) {
if (track->used && !track->toBeRemoved && (strcasecmp(track->soundName, soundName) == 0)) {
count++;
}
}
@ -262,6 +242,7 @@ int Imuse::getCountPlayedTracks(const char *soundName) {
}
void Imuse::selectVolumeGroup(const char *soundName, int volGroupId) {
Common::StackLock lock(_mutex);
Track *changeTrack;
assert((volGroupId >= 1) && (volGroupId <= 4));
@ -277,6 +258,7 @@ void Imuse::selectVolumeGroup(const char *soundName, int volGroupId) {
}
void Imuse::setFadeVolume(const char *soundName, int destVolume, int duration) {
Common::StackLock lock(_mutex);
Track *changeTrack;
changeTrack = findTrack(soundName);
@ -291,6 +273,7 @@ void Imuse::setFadeVolume(const char *soundName, int destVolume, int duration) {
}
void Imuse::setFadePan(const char *soundName, int destPan, int duration) {
Common::StackLock lock(_mutex);
Track *changeTrack;
changeTrack = findTrack(soundName);
@ -305,7 +288,7 @@ void Imuse::setFadePan(const char *soundName, int destPan, int duration) {
}
char *Imuse::getCurMusicSoundName() {
StackLock lock(_mutex);
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
@ -315,65 +298,90 @@ char *Imuse::getCurMusicSoundName() {
return NULL;
}
int Imuse::getCurMusicPan() {
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
return track->pan / 1000;
}
}
return NULL;
}
int Imuse::getCurMusicVol() {
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
return track->vol / 1000;
}
}
return NULL;
}
void Imuse::fadeOutMusic(int duration) {
StackLock lock(_mutex);
Common::StackLock lock(_mutex);
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
cloneToFadeOutTrack(track, duration);
track->toBeRemoved = true;
flushTrack(track);
return;
}
}
}
Imuse::Track *Imuse::cloneToFadeOutTrack(Track *track, int fadeDelay) {
assert(track);
Track *fadeTrack = 0;
void Imuse::fadeOutMusicAndStartNew(int fadeDelay, const char *filename, int hookId, int vol, int pan) {
Common::StackLock lock(_mutex);
{
StackLock lock(_mutex);
for (int l = MAX_IMUSE_TRACKS; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
if (!_track[l]->used) {
fadeTrack = _track[l];
break;
}
for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
Track *track = _track[l];
if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
startMusicWithOtherPos(filename, 0, vol, pan, track);
cloneToFadeOutTrack(track, fadeDelay);
flushTrack(track);
break;
}
if (fadeTrack == 0)
error("Imuse::cloneTofadeTrackId() Can't find free fade track");
}
}
fadeTrack->pan = track->pan;
fadeTrack->vol = track->vol;
fadeTrack->volGroupId = track->volGroupId;
fadeTrack->priority = track->priority;
fadeTrack->dataOffset = track->dataOffset;
fadeTrack->regionOffset = track->regionOffset;
fadeTrack->curRegion = track->curRegion;
fadeTrack->curHookId = track->curHookId;
fadeTrack->iteration = track->iteration;
fadeTrack->mixerFlags = track->mixerFlags;
fadeTrack->mixerVol = track->mixerVol;
fadeTrack->mixerPan = track->mixerPan;
fadeTrack->toBeRemoved = track->toBeRemoved;
fadeTrack->readyToRemove = track->readyToRemove;
fadeTrack->started = track->started;
strcpy(fadeTrack->soundName, track->soundName);
fadeTrack->soundHandle = _sound->cloneSound(track->soundHandle);
assert(fadeTrack->soundHandle);
fadeTrack->volFadeDelay = fadeDelay;
fadeTrack->volFadeDest = 0;
fadeTrack->volFadeStep = (fadeTrack->volFadeDest - fadeTrack->vol) * 60 * (1000 / _callbackFps) / (1000 * fadeDelay);
fadeTrack->volFadeUsed = true;
fadeTrack->panFadeDelay = 0;
fadeTrack->panFadeDest = 0;
fadeTrack->panFadeStep = 0;
fadeTrack->panFadeUsed = false;
Track *Imuse::cloneToFadeOutTrack(Track *track, int fadeDelay) {
assert(track);
Track *fadeTrack;
if (track->toBeRemoved) {
error("cloneToFadeOutTrack: Tried to clone a track to be removed, please bug report");
return NULL;
}
// setup 1 second stream wrapped buffer
int32 streamBufferSize = fadeTrack->iteration;
fadeTrack->stream = makeAppendableAudioStream(_sound->getFreq(fadeTrack->soundHandle), fadeTrack->mixerFlags, streamBufferSize);
g_mixer->playInputStream(&fadeTrack->handle, fadeTrack->stream, false, -1, fadeTrack->vol / 1000, fadeTrack->pan, false);
fadeTrack->started = true;
assert(track->trackId < MAX_IMUSE_TRACKS);
fadeTrack = _track[track->trackId + MAX_IMUSE_TRACKS];
if (fadeTrack->used) {
flushTrack(fadeTrack);
g_mixer->stopHandle(fadeTrack->handle);
}
// Clone the settings of the given track
memcpy(fadeTrack, track, sizeof(Track));
fadeTrack->trackId = track->trackId + MAX_IMUSE_TRACKS;
// Clone the sound.
// leaving bug number for now #1635361
ImuseSndMgr::SoundDesc *soundDesc = _sound->cloneSound(track->soundDesc);
assert(soundDesc);
track->soundDesc = soundDesc;
// Set the volume fading parameters to indicate a fade out
fadeTrack->volFadeDelay = fadeDelay;
fadeTrack->volFadeDest = 0;
fadeTrack->volFadeStep = (fadeTrack->volFadeDest - fadeTrack->vol) * 60 * (1000 / _callbackFps) / (1000 * fadeDelay);
fadeTrack->volFadeUsed = true;
// Create an appendable output buffer
fadeTrack->stream = Audio::makeAppendableAudioStream(_sound->getFreq(fadeTrack->soundDesc), makeMixerFlags(fadeTrack->mixerFlags));
g_mixer->playInputStream(track->getType(), &fadeTrack->handle, fadeTrack->stream, -1, fadeTrack->getVol(), fadeTrack->getPan());
fadeTrack->used = true;
return fadeTrack;

View File

@ -0,0 +1,98 @@
/* Residual - Virtual machine to run LucasArts' 3D adventure games
* Copyright (C) 2003-2006 The ScummVM-Residual Team (www.scummvm.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* $URL$
* $Id$
*
*/
#ifndef IMUSE_TRACK_H
#define IMUSE_TRACK_H
#include "common/sys.h"
#include "common/platform.h"
#include "common/debug.h"
#include "engine/lua.h"
#include "mixer/mixer.h"
#include "mixer/audiostream.h"
#include "engine/imuse/imuse_sndmgr.h"
#include "engine/imuse/imuse_mcmp_mgr.h"
enum {
kFlagUnsigned = 1 << 0,
kFlag16Bits = 1 << 1,
kFlagLittleEndian = 1 << 2,
kFlagStereo = 1 << 3,
kFlagReverseStereo = 1 << 4
};
struct Track {
int trackId;
int32 pan;
int32 panFadeDest;
int32 panFadeStep;
int32 panFadeDelay;
bool panFadeUsed;
int32 vol;
int32 volFadeDest;
int32 volFadeStep;
int32 volFadeDelay;
bool volFadeUsed;
char soundName[32];
bool used;
bool toBeRemoved;
int32 priority;
int32 regionOffset;
int32 dataOffset;
int32 curRegion;
int32 curHookId;
int32 volGroupId;
int32 feedSize;
int32 mixerFlags;
ImuseSndMgr::SoundDesc *soundDesc;
Audio::SoundHandle handle;
Audio::AppendableAudioStream *stream;
Track() : used(false), stream(NULL) {
soundName[0] = 0;
}
int getPan() const { return (pan != 6400) ? 2 * (pan / 1000) - 127 : 0; }
int getVol() const { return vol / 1000; }
Audio::Mixer::SoundType getType() const {
Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType;
if (volGroupId == IMUSE_VOLGRP_VOICE)
type = Audio::Mixer::kSpeechSoundType;
else if (volGroupId == IMUSE_VOLGRP_SFX)
type = Audio::Mixer::kSFXSoundType;
else if (volGroupId == IMUSE_VOLGRP_MUSIC)
type = Audio::Mixer::kMusicSoundType;
else if (volGroupId == IMUSE_VOLGRP_BGND)
type = Audio::Mixer::kPlainSoundType;
else if (volGroupId == IMUSE_VOLGRP_ACTION)
type = Audio::Mixer::kPlainSoundType;
return type;
}
};
#endif

View File

@ -42,6 +42,8 @@
#include "engine/imuse/imuse.h"
#include "mixer/mixer.h"
#include <cstdio>
#include <cmath>
#include <zlib.h>
@ -1880,7 +1882,7 @@ static void ImStartSound() {
group = check_int(3);
// Start the sound with the appropriate settings
if (g_imuse->startSound(soundName, group, 0, 127, 0, priority)) {
if (g_imuse->startSound(soundName, group, 0, 127, 0, priority, NULL)) {
lua_pushstring(soundName);
} else {
// Allow soft failing when loading sounds, hard failing when not
@ -1929,32 +1931,32 @@ static void ImSetVoiceEffect() {
static void ImSetMusicVol() {
DEBUG_FUNCTION();
g_imuse->setGroupMusicVolume(check_int(1));
g_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, check_int(1));
}
static void ImGetMusicVol() {
DEBUG_FUNCTION();
lua_pushnumber(g_imuse->getGroupMusicVolume());
lua_pushnumber(g_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType));
}
static void ImSetVoiceVol() {
DEBUG_FUNCTION();
g_imuse->setGroupVoiceVolume(check_int(1));
g_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, check_int(1));
}
static void ImGetVoiceVol() {
DEBUG_FUNCTION();
lua_pushnumber(g_imuse->getGroupVoiceVolume());
lua_pushnumber(g_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType));
}
static void ImSetSfxVol() {
DEBUG_FUNCTION();
g_imuse->setGroupSfxVolume(check_int(1));
g_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, check_int(1));
}
static void ImGetSfxVol() {
DEBUG_FUNCTION();
lua_pushnumber(g_imuse->getGroupSfxVolume());
lua_pushnumber(g_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType));
}
static void ImSetParam() {
@ -2961,7 +2963,7 @@ static void GetSaveGameImage() {
filename = luaL_check_string(1);
SaveGame *savedState = new SaveGame(filename, false);
dataSize = savedState->beginSection('SIMG');
data = (char *)malloc(dataSize);
data = new char[dataSize];
savedState->read(data, dataSize);
screenshot = new Bitmap(data, width, height, "screenshot");
if (screenshot) {

View File

@ -58,6 +58,8 @@ enDebugLevels debugLevel = DEBUG_NONE;
static bool g_lua_initialized = false;
Driver *g_driver = NULL;
DefaultTimerManager *g_timer = NULL;
Audio::Mixer *g_mixer = NULL;
static bool parseBoolStr(const char *val) {
if (val == NULL || val[0] == 0)
@ -168,12 +170,18 @@ needshelp:
g_driver = new DriverTinyGL(640, 480, 16, fullscreen);
else
g_driver = new DriverGL(640, 480, 24, fullscreen);
g_timer = new DefaultTimerManager();
g_driver->setTimerCallback();
g_mixer = new Audio::Mixer();
g_driver->setSoundCallback(Audio::Mixer::mixCallback, g_mixer);
g_mixer->setReady(true);
g_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, 127);
g_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, Audio::Mixer::kMaxMixerVolume);
g_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, Audio::Mixer::kMaxMixerVolume);
g_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
g_engine = new Engine();
g_resourceloader = new ResourceLoader();
g_localizer = new Localizer();
g_mixer = new SoundMixer();
g_mixer->setVolume(255);
g_timer = new Timer();
g_smush = new Smush();
g_imuse = new Imuse(20);
@ -226,6 +234,8 @@ void quit() {
delete g_registry;
g_registry = NULL;
}
if (g_driver)
g_driver->clearTimerCallback();
delete g_smush;
g_smush = NULL;
delete g_imuse;

View File

@ -68,17 +68,17 @@ uint32 SaveGame::beginSection(uint32 sectionTag) {
error("Tried to begin a new save game section with ending old section!");
_currentSection = sectionTag;
_sectionSize = 0;
_sectionBuffer = (char *) malloc(_sectionSize);
_sectionBuffer = new char[_sectionSize];
if (!_saving) {
uint32 tag = 0;
while (tag != sectionTag) {
free(_sectionBuffer);
delete[] _sectionBuffer;
gzread(_fileHandle, &tag, sizeof(uint32));
if (tag == SAVEGAME_FOOTERTAG)
error("Unable to find requested section of savegame!");
gzread(_fileHandle, &_sectionSize, sizeof(uint32));
_sectionBuffer = (char *)malloc(_sectionSize);
_sectionBuffer = new char[_sectionSize];
gzread(_fileHandle, _sectionBuffer, _sectionSize);
}
}
@ -94,8 +94,8 @@ void SaveGame::endSection() {
gzwrite(_fileHandle, &_sectionSize, sizeof(uint32));
gzwrite(_fileHandle, _sectionBuffer, _sectionSize);
}
free(_sectionBuffer);
_currentSection = 0;
delete[] _sectionBuffer;
_currentSection = NULL;
}
void SaveGame::read(void *data, int size) {

View File

@ -624,7 +624,7 @@ void Blocky16::init(int width, int height) {
// lol, byeruba, crushed, eldepot, heltrain, hostage
// but for tb_kitty.snm 5700 bytes is needed
_deltaSize = _frameSize * 3 + 5700;
_deltaBuf = (byte *)malloc(_deltaSize);
_deltaBuf = new byte[_deltaSize];
memset(_deltaBuf, 0, _deltaSize);
_deltaBufs[0] = _deltaBuf;
_deltaBufs[1] = _deltaBuf + _frameSize;
@ -632,8 +632,8 @@ void Blocky16::init(int width, int height) {
}
Blocky16::Blocky16() {
_tableBig = (byte *)malloc(99328);
_tableSmall = (byte *)malloc(32768);
_tableBig = new byte[99328];
_tableSmall = new byte[32768];
memset(_tableBig, 0, 99328);
memset(_tableSmall, 0, 32768);
_deltaBuf = NULL;
@ -642,7 +642,7 @@ Blocky16::Blocky16() {
void Blocky16::deinit() {
_lastTableWidth = -1;
if (_deltaBuf) {
free(_deltaBuf);
delete[] _deltaBuf;
_deltaSize = 0;
_deltaBuf = NULL;
_deltaBufs[0] = NULL;
@ -653,11 +653,11 @@ void Blocky16::deinit() {
Blocky16::~Blocky16() {
deinit();
if (_tableBig) {
free(_tableBig);
delete[] _tableBig;
_tableBig = NULL;
}
if (_tableSmall) {
free(_tableSmall);
delete[] _tableSmall;
_tableSmall = NULL;
}
}

View File

@ -29,6 +29,7 @@
#include "engine/resource.h"
#include "engine/engine.h"
#include "engine/backend/driver.h"
#include "engine/imuse/imuse_track.h"
#include "mixer/mixer.h"
@ -83,8 +84,8 @@ void Smush::init() {
assert(!_internalBuffer);
assert(!_externalBuffer);
_internalBuffer = (byte *)malloc(_width * _height * 2);
_externalBuffer = (byte *)malloc(_width * _height * 2);
_internalBuffer = new byte[_width * _height * 2];
_externalBuffer = new byte[_width * _height * 2];
vimaInit(smushDestTable);
g_timer->installTimerProc(&timerCallback, _speed, NULL);
@ -94,16 +95,16 @@ void Smush::deinit() {
g_timer->removeTimerProc(&timerCallback);
if (_internalBuffer) {
free(_internalBuffer);
delete[] _internalBuffer;
_internalBuffer = NULL;
}
if (_externalBuffer) {
free(_externalBuffer);
delete[] _externalBuffer;
_externalBuffer = NULL;
}
if (_videoLooping && _startPos != NULL) {
free(_startPos->tmpBuf);
free(_startPos);
delete[] _startPos->tmpBuf;
delete[] _startPos;
_startPos = NULL;
}
if (_stream) {
@ -118,20 +119,22 @@ void Smush::deinit() {
}
void Smush::handleWave(const byte *src, uint32 size) {
int16 *dst = (int16 *)malloc(size * _channels * 2);
int16 *dst = new int16[size * _channels];
decompressVima(src, dst, size * _channels * 2, smushDestTable);
int flags = SoundMixer::FLAG_16BITS;
int flags = Audio::Mixer::FLAG_16BITS;
if (_channels == 2)
flags |= SoundMixer::FLAG_STEREO;
flags |= Audio::Mixer::FLAG_STEREO;
if (!_stream) {
_stream = makeAppendableAudioStream(_freq, flags, 500000);
g_mixer->playInputStream(&_soundHandle, _stream, true);
_stream = Audio::makeAppendableAudioStream(_freq, flags);
g_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_soundHandle, _stream);
}
if (g_mixer->isReady()) {
_stream->queueBuffer((byte *)dst, size * _channels * 2);
} else {
delete[] dst;
}
if (_stream)
_stream->append((byte *)dst, size * _channels * 2);
free(dst);
}
void Smush::handleFrame() {
@ -162,7 +165,7 @@ void Smush::handleFrame() {
byte *data;
size = _file.readUint32BE();
data = (byte *)malloc(size);
data = new byte[size];
_file.read(data, size);
anno = (char *)data;
if (strncmp(anno, ANNO_HEADER, sizeof(ANNO_HEADER)-1) == 0) {
@ -185,13 +188,13 @@ void Smush::handleFrame() {
if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
printf("Announcement header not understood: %s\n", anno);
}
free(anno);
delete[] anno;
tag = _file.readUint32BE();
}
assert(tag == MKID_BE('FRME'));
size = _file.readUint32BE();
byte *frame = (byte *)malloc(size);
byte *frame = new byte[size];
_file.read(frame, size);
do {
@ -209,7 +212,7 @@ void Smush::handleFrame() {
error("Smush::handleFrame() unknown tag");
}
} while (pos < size);
free(frame);
delete[] frame;
memcpy(_externalBuffer, _internalBuffer, _width * _height * 2);
_updateNeeded = true;
@ -234,7 +237,7 @@ void Smush::handleFramesHeader() {
tag = _file.readUint32BE();
assert(tag == MKID_BE('FLHD'));
size = _file.readUint32BE();
byte *f_header = (byte*)malloc(size);
byte *f_header = new byte[size];
_file.read(f_header, size);
do {
@ -248,7 +251,7 @@ void Smush::handleFramesHeader() {
error("Smush::handleFramesHeader() unknown tag");
}
} while (pos < size);
free(f_header);
delete[] f_header;
}
bool Smush::setupAnim(const char *file, int x, int y) {
@ -267,7 +270,7 @@ bool Smush::setupAnim(const char *file, int x, int y) {
assert(tag == MKID_BE('SHDR'));
size = _file.readUint32BE();
byte *s_header = (byte *)malloc(size);
byte *s_header = new byte[size];
_file.read(s_header, size);
_nbframes = READ_LE_UINT32(s_header + 2);
int width = READ_LE_UINT16(s_header + 8);
@ -301,7 +304,7 @@ bool Smush::setupAnim(const char *file, int x, int y) {
}
_videoLooping = SMUSH_LOOPMOVIE(flags);
_startPos = NULL; // Set later
free(s_header);
delete[] s_header;
return true;
}
@ -347,10 +350,10 @@ struct SavePos *zlibFile::getPos() {
warning("zlibFile::open() unable to find start position! %m");
return NULL;
}
pos = (struct SavePos *) malloc(sizeof(struct SavePos));
pos = new SavePos;
pos->filePos = position;
inflateCopy(&pos->streamBuf, &_stream);
pos->tmpBuf = (char *)calloc(1, BUFFER_SIZE);
pos->tmpBuf = new char[BUFFER_SIZE];
memcpy(pos->tmpBuf, _inBuf, BUFFER_SIZE);
return pos;
}
@ -446,7 +449,7 @@ void zlibFile::close() {
}
if (_inBuf) {
free(_inBuf);
delete[] _inBuf;
_inBuf = NULL;
}
}

View File

@ -70,8 +70,8 @@ private:
int32 _nbframes;
Blocky16 _blocky16;
zlibFile _file;
PlayingSoundHandle _soundHandle;
AppendableAudioStream *_stream;
Audio::SoundHandle _soundHandle;
Audio::AppendableAudioStream *_stream;
int32 _frame;
bool _updateNeeded;

View File

@ -139,7 +139,7 @@ void TextObject::createBitmap() {
message += msg[i];
}
_textObjectHandle = (Driver::TextObjectHandle **)malloc(sizeof(long) * _numberLines);
_bitmapWidthPtr = (int *)malloc(sizeof(int) * _numberLines);
_bitmapWidthPtr = new int[_numberLines];
for (int j = 0; j < _numberLines; j++) {
int nextLinePos = message.find_first_of('\n');
@ -188,13 +188,13 @@ void TextObject::destroyBitmap() {
if (_textObjectHandle) {
for (int i = 0; i < _numberLines; i++) {
g_driver->destroyTextBitmap(_textObjectHandle[i]);
delete _textObjectHandle[i];
delete[] _textObjectHandle[i];
}
free(_textObjectHandle);
_textObjectHandle = NULL;
}
if (_bitmapWidthPtr) {
free(_bitmapWidthPtr);
delete[] _bitmapWidthPtr;
_bitmapWidthPtr = NULL;
}
}