synced with scummvm
svn-id: r4821
This commit is contained in:
parent
fa181fcd8b
commit
9f993a1d29
46 changed files with 5117 additions and 371 deletions
|
@ -489,8 +489,8 @@ void SoundDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data)
|
||||||
|
|
||||||
scumm->_imuse->set_music_volume(_soundVolumeMusic);
|
scumm->_imuse->set_music_volume(_soundVolumeMusic);
|
||||||
scumm->_imuse->set_master_volume(_soundVolumeMaster);
|
scumm->_imuse->set_master_volume(_soundVolumeMaster);
|
||||||
scumm->_mixer->set_volume(_soundVolumeSfx);
|
scumm->_mixer->setVolume(_soundVolumeSfx);
|
||||||
scumm->_mixer->set_music_volume(_soundVolumeMusic);
|
scumm->_mixer->setMusicVolume(_soundVolumeMusic);
|
||||||
|
|
||||||
scummcfg->set("master_volume", _soundVolumeMaster);
|
scummcfg->set("master_volume", _soundVolumeMaster);
|
||||||
scummcfg->set("music_volume", _soundVolumeMusic);
|
scummcfg->set("music_volume", _soundVolumeMusic);
|
||||||
|
|
|
@ -621,8 +621,8 @@ void Gui::handleSoundDialogCommand(int cmd)
|
||||||
|
|
||||||
_s->_imuse->set_music_volume(_s->_sound->_sound_volume_music);
|
_s->_imuse->set_music_volume(_s->_sound->_sound_volume_music);
|
||||||
_s->_imuse->set_master_volume(_s->_sound->_sound_volume_master);
|
_s->_imuse->set_master_volume(_s->_sound->_sound_volume_master);
|
||||||
_s->_mixer->set_volume(_s->_sound->_sound_volume_sfx);
|
_s->_mixer->setVolume(_s->_sound->_sound_volume_sfx);
|
||||||
_s->_mixer->set_music_volume(_s->_sound->_sound_volume_music);
|
_s->_mixer->setMusicVolume(_s->_sound->_sound_volume_music);
|
||||||
|
|
||||||
scummcfg->set("master_volume", _s->_sound->_sound_volume_master);
|
scummcfg->set("master_volume", _s->_sound->_sound_volume_master);
|
||||||
scummcfg->set("music_volume", _s->_sound->_sound_volume_music);
|
scummcfg->set("music_volume", _s->_sound->_sound_volume_music);
|
||||||
|
|
|
@ -3302,7 +3302,7 @@ void IMuseAdlib::init(IMuseInternal *eng, OSystem *syst)
|
||||||
adlib_write(0xBD, 0x00);
|
adlib_write(0xBD, 0x00);
|
||||||
create_lookup_table();
|
create_lookup_table();
|
||||||
|
|
||||||
_mixer->setup_premix(this, premix_proc);
|
_mixer->setupPremix(this, premix_proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMuseAdlib::adlib_write(byte port, byte value)
|
void IMuseAdlib::adlib_write(byte port, byte value)
|
||||||
|
|
|
@ -1467,7 +1467,7 @@ void SmushPlayer::startVideo(short int arg, byte *videoFile) {
|
||||||
for (idx = 0; idx < MAX_STREAMER; idx++) {
|
for (idx = 0; idx < MAX_STREAMER; idx++) {
|
||||||
if (_imusTrk[idx] != 0) {
|
if (_imusTrk[idx] != 0) {
|
||||||
if (_imusNewMixer[idx]) {
|
if (_imusNewMixer[idx]) {
|
||||||
_scumm->_mixer->play_stream(NULL, idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]);
|
_scumm->_mixer->playStream(NULL, idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]);
|
||||||
} else {
|
} else {
|
||||||
_scumm->_mixer->append(idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]);
|
_scumm->_mixer->append(idx, _imusBuf[idx], _imusFinalSize[idx], _imusRate[idx], _imusFlags[idx]);
|
||||||
}
|
}
|
||||||
|
@ -1479,7 +1479,7 @@ void SmushPlayer::startVideo(short int arg, byte *videoFile) {
|
||||||
for (idx = 0; idx < MAX_STREAMER; idx++) {
|
for (idx = 0; idx < MAX_STREAMER; idx++) {
|
||||||
if (_psadTrk[idx] != 0) {
|
if (_psadTrk[idx] != 0) {
|
||||||
if (_strkNewMixer[idx]) {
|
if (_strkNewMixer[idx]) {
|
||||||
_scumm->_mixer->play_stream(NULL, idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playStream(NULL, idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
} else {
|
} else {
|
||||||
_scumm->_mixer->append(idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->append(idx, _strkBuf[idx], _strkFinalSize[idx], _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -597,7 +597,7 @@ void Scumm::saveOrLoad(Serializer *s)
|
||||||
int var98Backup;
|
int var98Backup;
|
||||||
|
|
||||||
if (_mixer && !s->isSaving())
|
if (_mixer && !s->isSaving())
|
||||||
_mixer->stop_all();
|
_mixer->stopAll();
|
||||||
|
|
||||||
if (_current_version == VER_V9)
|
if (_current_version == VER_V9)
|
||||||
s->saveLoadEntries(this, mainEntriesV9);
|
s->saveLoadEntries(this, mainEntriesV9);
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "scumm.h"
|
#include "scumm.h"
|
||||||
#include "actor.h"
|
#include "actor.h"
|
||||||
#include "smush.h"
|
#include "smush/player.h"
|
||||||
|
#include "smush/scumm_renderer.h"
|
||||||
|
|
||||||
#include "sound/mididrv.h"
|
#include "sound/mididrv.h"
|
||||||
#include "scumm/imuse.h"
|
#include "scumm/imuse.h"
|
||||||
|
@ -2699,7 +2700,6 @@ void Scumm::o6_miscOps()
|
||||||
Actor *a;
|
Actor *a;
|
||||||
|
|
||||||
IMuse *se = _imuse; //yazoo: not very nice
|
IMuse *se = _imuse; //yazoo: not very nice
|
||||||
SmushPlayer * sp;
|
|
||||||
|
|
||||||
getStackList(args, sizeof(args) / sizeof(args[0]));
|
getStackList(args, sizeof(args) / sizeof(args[0]));
|
||||||
|
|
||||||
|
@ -2708,11 +2708,15 @@ void Scumm::o6_miscOps()
|
||||||
case 4:
|
case 4:
|
||||||
grabCursor(args[1], args[2], args[3], args[4]);
|
grabCursor(args[1], args[2], args[3], args[4]);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6: {
|
||||||
sp = new SmushPlayer(this);
|
ScummRenderer sr(this);
|
||||||
sp->startVideo(args[1], getStringAddressVar(VAR_VIDEONAME));
|
SmushPlayer sp(&sr);
|
||||||
delete sp;
|
char filename[512];
|
||||||
break;
|
strcpy(filename, _gameDataPath);
|
||||||
|
strcat(filename, "video/");
|
||||||
|
strcat(filename, (char*)getStringAddressVar(VAR_VIDEONAME));
|
||||||
|
sp.play(filename);
|
||||||
|
}
|
||||||
case 7:
|
case 7:
|
||||||
warning("o6_miscOps: stub7()");
|
warning("o6_miscOps: stub7()");
|
||||||
break;
|
break;
|
||||||
|
|
221
scumm/smush/blitter.cpp
Normal file
221
scumm/smush/blitter.cpp
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "blitter.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h> // for memcpy
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(x, y) ((x) > (y) ? (y) : (x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Blitter::Blitter(char * ptr, const Point & dstsize, const Rect & src) :
|
||||||
|
_ptr(ptr),
|
||||||
|
_clip(dstsize),
|
||||||
|
_src(src),
|
||||||
|
_cur(src.left(), src.top()),
|
||||||
|
_outside(false) {
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
_clipped = 0;
|
||||||
|
_clippedBlock = 0;
|
||||||
|
#endif
|
||||||
|
assert(_ptr);
|
||||||
|
assert(_clip.getX() > 0 && _clip.getY() > 0);
|
||||||
|
assert(_src.width() > 0 && _src.height() > 0);
|
||||||
|
assert(_src.left() < _clip.getX() && _src.right() <= _clip.getX());
|
||||||
|
assert(_src.top() < _clip.getY() && _src.bottom() <= _clip.getY());
|
||||||
|
_offset = _ptr + _clip.getX() * _cur.getY() + _cur.getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
Blitter::~Blitter() {
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
if(_clipped || _clippedBlock) {
|
||||||
|
debug(3, "blitter clipped %d pixels and %d blocks", _clipped, _clippedBlock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::advance(int x, int y) {
|
||||||
|
if(y != 0) {
|
||||||
|
_cur.set(_src.left() + x, _cur.getY() + y);
|
||||||
|
} else {
|
||||||
|
_cur.getX() += x;
|
||||||
|
if(_cur.getX() >= _src.right()) {
|
||||||
|
_cur.set(_src.left(), _cur.getY()+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_offset = _ptr + _clip.getX() * _cur.getY() + _cur.getX();
|
||||||
|
_outside = ! _src.isInside(_cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::advanceBlock(int x, int y) {
|
||||||
|
advance(x*4, y*4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::put(char data) {
|
||||||
|
if(!_outside) {
|
||||||
|
*_offset = data;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
else _clipped ++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::put(char data, unsigned int len) {
|
||||||
|
while(len) {
|
||||||
|
if(_outside) {
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
_clipped += len;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int l = min((int)len, min(_clip.getX() - _cur.getX(), _src.right() - _cur.getX()));
|
||||||
|
len -= l;
|
||||||
|
memset(_offset, data, l);
|
||||||
|
advance(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::blit(char * ptr, unsigned int len) {
|
||||||
|
while(len) {
|
||||||
|
if(_outside) {
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
_clipped += len;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int l = min((int)len, min(_clip.getX() - _cur.getX(), _src.right() - _cur.getX()));
|
||||||
|
len -= l;
|
||||||
|
memcpy(_offset, ptr, l);
|
||||||
|
ptr += l;
|
||||||
|
advance(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::blit(Chunck & src, unsigned int len) {
|
||||||
|
while(len) {
|
||||||
|
if(_outside) {
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
_clipped += len;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int l = min((int)len, min(_clip.getX() -_cur.getX(), _src.right() - _cur.getX()));
|
||||||
|
len -= l;
|
||||||
|
src.read(_offset, l);
|
||||||
|
advance(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::putBlock(unsigned int data) {
|
||||||
|
if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
|
||||||
|
assert((_clip.getX() & 3) == 0);
|
||||||
|
unsigned int * dst = (unsigned int *)_offset;
|
||||||
|
int line_size = _clip.getX() >> 2;
|
||||||
|
|
||||||
|
*dst = data; dst += line_size;
|
||||||
|
*dst = data; dst += line_size;
|
||||||
|
*dst = data; dst += line_size;
|
||||||
|
*dst = data;
|
||||||
|
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
} else {
|
||||||
|
_clippedBlock ++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
advanceBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::putBlock(unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4) {
|
||||||
|
if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
|
||||||
|
assert((_clip.getX() & 3) == 0);
|
||||||
|
unsigned int * dst = (unsigned int *)_offset;
|
||||||
|
int line_size = _clip.getX() >> 2;
|
||||||
|
|
||||||
|
*dst = d4; dst += line_size;
|
||||||
|
*dst = d3; dst += line_size;
|
||||||
|
*dst = d2; dst += line_size;
|
||||||
|
*dst = d1;
|
||||||
|
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
} else {
|
||||||
|
_clippedBlock ++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
advanceBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::putBlock(unsigned char * data) {
|
||||||
|
if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
|
||||||
|
assert((_clip.getX() & 3) == 0);
|
||||||
|
unsigned int * dst = (unsigned int *)_offset;
|
||||||
|
int line_size = _clip.getX() >> 2;
|
||||||
|
unsigned int * src = (unsigned int *)data;
|
||||||
|
*dst = *src++; dst += line_size;
|
||||||
|
*dst = *src++; dst += line_size;
|
||||||
|
*dst = *src++; dst += line_size;
|
||||||
|
*dst = *src++;
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
} else {
|
||||||
|
_clippedBlock ++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
advanceBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::putBlock(Chunck & src) {
|
||||||
|
if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) { // This is clipping
|
||||||
|
assert((_clip.getX() & 3) == 0);
|
||||||
|
unsigned int * dst = (unsigned int *)_offset;
|
||||||
|
int line_size = _clip.getX() >> 2;
|
||||||
|
*dst = src.getDword(); dst += line_size;
|
||||||
|
*dst = src.getDword(); dst += line_size;
|
||||||
|
*dst = src.getDword(); dst += line_size;
|
||||||
|
*dst = src.getDword();
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
} else {
|
||||||
|
_clippedBlock ++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
advanceBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::blockCopy(int offset) {
|
||||||
|
if(_cur.getX() + 3 < _src.right() && _cur.getY() + 3 < _src.bottom()) {// This is clipping
|
||||||
|
char * dst = _offset;
|
||||||
|
*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
|
||||||
|
dst += _clip.getX();
|
||||||
|
*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
|
||||||
|
dst += _clip.getX();
|
||||||
|
*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
|
||||||
|
dst += _clip.getX();
|
||||||
|
*((unsigned int *)dst) = *((unsigned int *)(dst + offset));
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
} else {
|
||||||
|
_clippedBlock ++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
advanceBlock();
|
||||||
|
}
|
79
scumm/smush/blitter.h
Normal file
79
scumm/smush/blitter.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BLITTER_H_
|
||||||
|
#define __BLITTER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_CLIPPER
|
||||||
|
# define DEBUG_CLIPPER
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_CLIPPER
|
||||||
|
# error DEBUG_CLIPPER defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
class Chunck;
|
||||||
|
/*! @brief class for handling blitting on a frame buffer
|
||||||
|
|
||||||
|
This class allows to perform secure blitting to a frame buffer in several ways.
|
||||||
|
This means that clipping is performed, so that only the part that you want to modify can be modified.
|
||||||
|
*/
|
||||||
|
class Blitter {
|
||||||
|
private:
|
||||||
|
char * _ptr; //!< This is the pointer to the start of the frame buffer
|
||||||
|
char * _offset; //!< This is the current pointer in the frame buffer
|
||||||
|
Point _clip; //!< This is the size of the frame buffer (width/height)
|
||||||
|
Rect _src; //!< This is the size and position of the destination rectangle
|
||||||
|
Point _cur; //!< This is the current position in the destination rectangle
|
||||||
|
bool _outside; //!< flag that is set to \c true when the blitter reach the end of the destination rectangle
|
||||||
|
#ifdef DEBUG_CLIPPER
|
||||||
|
int _clipped;
|
||||||
|
int _clippedBlock;
|
||||||
|
#endif
|
||||||
|
public:
|
||||||
|
/*! @brief constructor
|
||||||
|
|
||||||
|
@param buffer the frame buffer to blit to
|
||||||
|
@param dstsize the size of the frame buffer
|
||||||
|
@param src the rectangle to blit to
|
||||||
|
*/
|
||||||
|
Blitter(char * buffer, const Point & dstsize, const Rect & src);
|
||||||
|
virtual ~Blitter();
|
||||||
|
void blit(char *, unsigned int); //!< This method allows to blit directly some data from a buffer
|
||||||
|
void blit(Chunck &, unsigned int); //!< This method allows to blit directly some data from a chunck
|
||||||
|
void put(char); //!< This method allows to blit one byte
|
||||||
|
void put(char, unsigned int); //!< This method allows to blit one byte several times
|
||||||
|
void advance(int = 1, int = 0); //!< This method allows to advance the current position in the blitter
|
||||||
|
void advanceBlock(int = 1, int = 0); //!< This method allows to advance the current position in the blitter in terms of blocks
|
||||||
|
void putBlock(unsigned int); //!< This method allows to blit one block from an int value repeated 4 time
|
||||||
|
void putBlock(Chunck &); //!< This method allows to blit one block directly read from a chunck
|
||||||
|
void putBlock(unsigned char *); //!< This method allows to blit one block directly from a buffer
|
||||||
|
void putBlock(unsigned int, unsigned int, unsigned int, unsigned int); //!< This method allows to blit one block from a 4 int value
|
||||||
|
void blockCopy(int); //!< This method allows to copy one block from another separated by the given offset
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
75
scumm/smush/brenderer.cpp
Normal file
75
scumm/smush/brenderer.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "brenderer.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
void BaseRenderer::clean() {
|
||||||
|
if(_data) {
|
||||||
|
delete[] _data;
|
||||||
|
_data = 0;
|
||||||
|
_width = _height = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseRenderer::BaseRenderer() :
|
||||||
|
_data(0),
|
||||||
|
_frame(0),
|
||||||
|
_nbframes(0),
|
||||||
|
_width(0),
|
||||||
|
_height(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseRenderer::~BaseRenderer() {
|
||||||
|
clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseRenderer::initFrame(const Point & p) {
|
||||||
|
clean();
|
||||||
|
_width = p.getX();
|
||||||
|
_height = p.getY();
|
||||||
|
assert(_width && _height);
|
||||||
|
_data = new char[_width * _height];
|
||||||
|
if(!_data) error("base_renderer unable to allocate frame buffer");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * BaseRenderer::lockFrame(int frame) {
|
||||||
|
_frame = frame;
|
||||||
|
if(!_data) error("no allocated image buffer in lock_frame");
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseRenderer::unlockFrame() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseRenderer::flipFrame() {
|
||||||
|
save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseRenderer::setPalette(const Palette & pal) {
|
||||||
|
_pal = pal;
|
||||||
|
return true;
|
||||||
|
}
|
86
scumm/smush/brenderer.h
Normal file
86
scumm/smush/brenderer.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BRENDERER_H_
|
||||||
|
#define __BRENDERER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "palette.h"
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
/*! @brief base class for easily creating ::renderer instances
|
||||||
|
|
||||||
|
This class implements some function available in the ::renderer abstract class, so that
|
||||||
|
creation of subclasses of ::renderer is easier.
|
||||||
|
*/
|
||||||
|
class BaseRenderer : public Renderer {
|
||||||
|
private:
|
||||||
|
Palette _pal; //!< The current palette
|
||||||
|
char * _data; //!< The current frame buffer
|
||||||
|
int _frame; //!< The current frame number
|
||||||
|
int _nbframes; //!< The number of frames in the animation
|
||||||
|
int _width; //!< The current frame's width
|
||||||
|
int _height; //!< The current frame's height
|
||||||
|
const char * _fname; //!< The filename of the animation being played
|
||||||
|
protected:
|
||||||
|
virtual void save(int frame = -1) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char * getFilename() const { return _fname; }; //!< accessor for animation filename
|
||||||
|
int getNbframes() const { return _nbframes; }; //!< accessor for number of frames
|
||||||
|
int getWidth() const { return _width; }; //!< accessor for current width
|
||||||
|
int getHeight() const { return _height; }; //!< accessor for current height
|
||||||
|
const Palette & pal() const { return _pal; }; //!< accessor for current palette
|
||||||
|
const char * data() const { return _data; }; //!< accessor for current frame buffer
|
||||||
|
void clean(); //!< memory cleanup (deletes frame buffer)
|
||||||
|
void setFrame(int f) { _frame = f; }; //!< allows to change the frame number
|
||||||
|
public:
|
||||||
|
int getFrame() const { return _frame; }; //!< accessor for current frame number
|
||||||
|
BaseRenderer();
|
||||||
|
virtual ~BaseRenderer();
|
||||||
|
|
||||||
|
virtual bool initFrame(const Point & size);
|
||||||
|
virtual char * lockFrame(int frame);
|
||||||
|
virtual bool unlockFrame();
|
||||||
|
virtual bool flipFrame();
|
||||||
|
virtual bool setPalette(const Palette & pal);
|
||||||
|
virtual bool startDecode(const char * fname, int version, int nbframes) { _fname = fname; _nbframes = nbframes; return true; }
|
||||||
|
virtual Mixer * getMixer() { return 0; };
|
||||||
|
virtual bool prematureClose() { return false; };
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! @brief A null ::renderer
|
||||||
|
|
||||||
|
This class completely implements ::renderer, without actually doing anything.
|
||||||
|
This class is useful for performance measurements.
|
||||||
|
*/
|
||||||
|
class NullRenderer : public BaseRenderer {
|
||||||
|
protected:
|
||||||
|
void save(int frame = -1) {};
|
||||||
|
public:
|
||||||
|
NullRenderer() {};
|
||||||
|
virtual ~NullRenderer() {};
|
||||||
|
bool wait(int ms) { return true; };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
157
scumm/smush/channel.h
Normal file
157
scumm/smush/channel.h
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CHANNEL_H_
|
||||||
|
#define __CHANNEL_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_CHANNEL
|
||||||
|
# define DEBUG_CHANNEL
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_CHANNEL
|
||||||
|
# error DEBUG_CHANNEL defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Chunck;
|
||||||
|
class ContChunck;
|
||||||
|
|
||||||
|
/*! @brief interface for a sound channel (a track)
|
||||||
|
|
||||||
|
This is the interface for sound channels.
|
||||||
|
*/
|
||||||
|
class _Channel {
|
||||||
|
public:
|
||||||
|
virtual ~_Channel() {};
|
||||||
|
// called by the smush_player
|
||||||
|
virtual bool appendData(Chunck & b, int size) = 0;
|
||||||
|
virtual bool setParameters(int, int, int, int) = 0;
|
||||||
|
virtual bool checkParameters(int, int, int, int, int) = 0;
|
||||||
|
// called by the mixer
|
||||||
|
virtual bool isTerminated() const = 0;
|
||||||
|
virtual int availableSoundData() const = 0;
|
||||||
|
virtual void getSoundData(short * sound_buffer, int size) = 0; // size is in sample
|
||||||
|
virtual void getSoundData(char * sound_buffer, int size) = 0;
|
||||||
|
virtual bool getParameters(int &rate, bool &stereo, bool &is_16bit) = 0;
|
||||||
|
virtual int getTrackIdentifier() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SaudChannel : public _Channel {
|
||||||
|
private:
|
||||||
|
int _track; //!< The track identifier
|
||||||
|
int _nbframes; //!< number of frames of the track (unused)
|
||||||
|
int _dataSize; //!< the size of the sound buffer
|
||||||
|
int _frequency; //!< the frequency target of the track (always 22050)
|
||||||
|
bool _inData; //!< are we processing data ?
|
||||||
|
bool _markReached; //!< set to \c true when the SMRK tag is reached
|
||||||
|
int _flags; //!< current flags of the track (unused)
|
||||||
|
int _volume; //!< the current track volume
|
||||||
|
int _balance; //!< the current track balance
|
||||||
|
int _index; //!< the current PSAD index (for coherency checking)
|
||||||
|
short _voltable[2][256]; //!< the precalculated volume table (stereo 16 bits)
|
||||||
|
unsigned char * _tbuffer; //!< data temporary buffer
|
||||||
|
int _tbufferSize; //!< temporary buffer size
|
||||||
|
unsigned char * _sbuffer; //!< sound buffer
|
||||||
|
int _sbufferSize; //!< sound buffer size
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void handleStrk(Chunck & c);
|
||||||
|
void handleSmrk(Chunck & c);
|
||||||
|
void handleShdr(Chunck & c);
|
||||||
|
bool handleSubTags(int & offset);
|
||||||
|
bool processBuffer();
|
||||||
|
void recalcVolumeTable();
|
||||||
|
|
||||||
|
public:
|
||||||
|
SaudChannel(int track, int freq);
|
||||||
|
virtual ~SaudChannel();
|
||||||
|
bool isTerminated() const;
|
||||||
|
bool setParameters(int duration, int flags, int vol1, int vol2);
|
||||||
|
bool checkParameters(int index, int duration, int flags, int vol1, int vol2);
|
||||||
|
bool appendData(Chunck & b, int size);
|
||||||
|
int availableSoundData() const;
|
||||||
|
void getSoundData(short * sound_buffer, int size);
|
||||||
|
void getSoundData(char * sound_buffer, int size) { error("16bit request for SAUD channel should never happen"); };
|
||||||
|
bool getParameters(int &rate, bool &stereo, bool &is_16bit) {
|
||||||
|
rate = _frequency;
|
||||||
|
stereo = true;
|
||||||
|
is_16bit = true;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
virtual int getTrackIdentifier() const { return _track; };
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! @brief class for a IACT sound ::channel (a The Dig track)
|
||||||
|
|
||||||
|
This class implements a channel specifically for The Dig.
|
||||||
|
|
||||||
|
\bug for unknown reason, some sound have a too long duration, or repeat themselves.
|
||||||
|
*/
|
||||||
|
class ImuseChannel : public _Channel {
|
||||||
|
private:
|
||||||
|
int _track; //!< the track number
|
||||||
|
unsigned char * _tbuffer; //!< data temporary buffer
|
||||||
|
int _tbufferSize; //!< temporary buffer size
|
||||||
|
unsigned char * _sbuffer; //!< sound buffer
|
||||||
|
int _sbufferSize; //!< sound buffer size
|
||||||
|
int _srbufferSize;
|
||||||
|
int _frequency; //!< the target frequency of the ::mixer
|
||||||
|
int _dataSize; //!< remaining size of sound data in the iMUS buffer
|
||||||
|
bool _inData;
|
||||||
|
|
||||||
|
int _bitsize; //!< the bitsize of the original data
|
||||||
|
int _rate; //!< the sampling rate of the original data
|
||||||
|
int _channels; //!< the number of channels of the original data
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int decode(int size, int &ret);
|
||||||
|
void decode();
|
||||||
|
bool processBuffer();
|
||||||
|
bool handleMap(Chunck &);
|
||||||
|
bool handleFormat(Chunck &);
|
||||||
|
bool handleText(Chunck &);
|
||||||
|
bool handleRegion(Chunck &);
|
||||||
|
bool handleStop(Chunck &);
|
||||||
|
bool handleSubTags(int & offset);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImuseChannel(int track, int freq);
|
||||||
|
virtual ~ImuseChannel();
|
||||||
|
bool isTerminated() const;
|
||||||
|
bool setParameters(int nbframes, int size, int unk1, int unk2);
|
||||||
|
bool checkParameters(int index, int nbframes, int size, int unk1, int unk2);
|
||||||
|
bool appendData(Chunck & b, int size);
|
||||||
|
int availableSoundData() const;
|
||||||
|
void getSoundData(short * sound_buffer, int size);
|
||||||
|
void getSoundData(char * sound_buffer, int size);
|
||||||
|
bool getParameters(int &rate, bool &stereo, bool &is_16bit) {
|
||||||
|
rate = _frequency;
|
||||||
|
stereo = (_channels == 2);
|
||||||
|
is_16bit = (_bitsize > 8);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
virtual int getTrackIdentifier() const { return _track; };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
288
scumm/smush/chunck.cpp
Normal file
288
scumm/smush/chunck.cpp
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "chunck.h"
|
||||||
|
|
||||||
|
#include <stdio.h> // for FILE, fopen, fclose, fseek and ftell
|
||||||
|
#include <string.h> // for memcpy
|
||||||
|
|
||||||
|
/*! @brief very small and fast wrapper for a ifstream.
|
||||||
|
|
||||||
|
implements reference counting, so that ::file_chunck does not leak memory !
|
||||||
|
*/
|
||||||
|
class FilePtr {
|
||||||
|
char * _filename;
|
||||||
|
FILE * _ifs;
|
||||||
|
int _refcount;
|
||||||
|
int _curPos;
|
||||||
|
public:
|
||||||
|
FilePtr(const char * fname) : _refcount(1), _curPos(0) {
|
||||||
|
debug(9, "FilePtr created for %s", fname);
|
||||||
|
_filename = strdup(fname);
|
||||||
|
_ifs = fopen(fname, "rb");
|
||||||
|
if(_ifs == NULL) error("FilePtr unable to read file \"%s\"", fname);
|
||||||
|
}
|
||||||
|
~FilePtr() {
|
||||||
|
debug(9, "FilePtr destroyed for %s", _filename);
|
||||||
|
free(_filename);
|
||||||
|
fclose(_ifs);
|
||||||
|
}
|
||||||
|
int tell() {
|
||||||
|
return _curPos;
|
||||||
|
}
|
||||||
|
bool seek(int pos) {
|
||||||
|
if(pos != _curPos) {
|
||||||
|
fseek(_ifs, pos, SEEK_SET);
|
||||||
|
_curPos = pos;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool read(void * ptr, int size) {
|
||||||
|
fread(ptr, size, 1, _ifs);
|
||||||
|
_curPos += size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void incRef() {
|
||||||
|
_refcount++;
|
||||||
|
}
|
||||||
|
void decRef() {
|
||||||
|
if(--_refcount == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char * Chunck::ChunckString(Chunck::type t) {
|
||||||
|
static char data[5];
|
||||||
|
data[0] = (char)((t >> 24) & 0xFF);
|
||||||
|
data[1] = (char)((t >> 16) & 0xFF);
|
||||||
|
data[2] = (char)((t >> 8) & 0xFF);
|
||||||
|
data[3] = (char)((t >> 0) & 0xFF);
|
||||||
|
data[4] = 0;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileChunck::FileChunck() : _data(0), _type(0), _size(0), _curPos(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
FileChunck::~FileChunck() {
|
||||||
|
if(_data) _data->decRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileChunck::FileChunck(const char * fname) {
|
||||||
|
_data = new FilePtr(fname);
|
||||||
|
_data->read(&_type, 4);
|
||||||
|
_type = TO_BE_32(_type);
|
||||||
|
_data->read(&_size, 4);
|
||||||
|
_size = TO_BE_32(_size);
|
||||||
|
_offset = _data->tell();
|
||||||
|
_curPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunck::type FileChunck::getType() const {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int FileChunck::getSize() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunck * FileChunck::subBlock() {
|
||||||
|
FileChunck * ptr = new FileChunck;
|
||||||
|
ptr->_data = _data;
|
||||||
|
_data->incRef();
|
||||||
|
_data->seek(_offset + _curPos);
|
||||||
|
unsigned int temp;
|
||||||
|
_data->read(&temp, 4);
|
||||||
|
ptr->_type = TO_BE_32(temp);
|
||||||
|
_data->read(&temp, 4);
|
||||||
|
ptr->_size = TO_BE_32(temp);
|
||||||
|
ptr->_offset = _offset + _curPos + 8;
|
||||||
|
ptr->_curPos = 0;
|
||||||
|
seek(8 + ptr->getSize());
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileChunck::eof() const {
|
||||||
|
return _curPos >= _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int FileChunck::tell() const {
|
||||||
|
return _curPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileChunck::seek(int delta, seek_type dir) {
|
||||||
|
switch(dir) {
|
||||||
|
case seek_cur:
|
||||||
|
_curPos += delta;
|
||||||
|
break;
|
||||||
|
case seek_start:
|
||||||
|
if(delta < 0) error("invalid seek request");
|
||||||
|
_curPos = (unsigned int)delta;
|
||||||
|
break;
|
||||||
|
case seek_end:
|
||||||
|
if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
|
||||||
|
_curPos = (unsigned int)(_size + delta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(_curPos > _size) {
|
||||||
|
error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileChunck::read(void * buffer, unsigned int size) {
|
||||||
|
if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
|
||||||
|
_data->seek(_offset + _curPos);
|
||||||
|
_data->read(buffer, size);
|
||||||
|
_curPos += size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char FileChunck::getChar() {
|
||||||
|
if(_curPos >= _size) error("invalid char read request");
|
||||||
|
_data->seek(_offset + _curPos);
|
||||||
|
char buffer;
|
||||||
|
_data->read(&buffer, sizeof(buffer));
|
||||||
|
_curPos+= sizeof(buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char FileChunck::getByte() {
|
||||||
|
if(_curPos >= _size) error("invalid byte read request");
|
||||||
|
_data->seek(_offset + _curPos);
|
||||||
|
unsigned char buffer;
|
||||||
|
_data->read(&buffer, sizeof(buffer));
|
||||||
|
_curPos+= sizeof(buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
short FileChunck::getShort() {
|
||||||
|
unsigned short buffer = getWord();
|
||||||
|
return *((short*)&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short FileChunck::getWord() {
|
||||||
|
if(_curPos >= _size - 1) error("invalid word read request");
|
||||||
|
_data->seek(_offset + _curPos);
|
||||||
|
unsigned short buffer;
|
||||||
|
_data->read(&buffer, sizeof(buffer));
|
||||||
|
_curPos+= sizeof(buffer);
|
||||||
|
return TO_LE_16(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int FileChunck::getDword() {
|
||||||
|
if(_curPos >= _size - 3) error("invalid dword read request");
|
||||||
|
_data->seek(_offset + _curPos);
|
||||||
|
unsigned int buffer;
|
||||||
|
_data->read(&buffer, sizeof(buffer));
|
||||||
|
_curPos+= sizeof(buffer);
|
||||||
|
return TO_LE_32(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContChunck::ContChunck(char * data) {
|
||||||
|
if(data == 0) error("Chunck() called with NULL pointer");
|
||||||
|
_type = (Chunck::type)READ_BE_UINT32(data);
|
||||||
|
_size = READ_BE_UINT32(data+4);
|
||||||
|
_data = data + sizeof(Chunck::type) + sizeof(unsigned int);
|
||||||
|
_curPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunck::type ContChunck::getType() const {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ContChunck::getSize() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunck * ContChunck::subBlock() {
|
||||||
|
ContChunck * ptr = new ContChunck(_data + _curPos);
|
||||||
|
seek(sizeof(Chunck::type) + sizeof(unsigned int) + ptr->getSize());
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContChunck::eof() const {
|
||||||
|
return _curPos >= _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ContChunck::tell() const {
|
||||||
|
return _curPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContChunck::seek(int delta, seek_type dir) {
|
||||||
|
switch(dir) {
|
||||||
|
case seek_cur:
|
||||||
|
_curPos += delta;
|
||||||
|
break;
|
||||||
|
case seek_start:
|
||||||
|
if(delta < 0) error("invalid seek request");
|
||||||
|
_curPos = (unsigned int)delta;
|
||||||
|
break;
|
||||||
|
case seek_end:
|
||||||
|
if(delta > 0 || (_size + delta) < 0) error("invalid seek request");
|
||||||
|
_curPos = (unsigned int)(_size + delta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(_curPos > _size) {
|
||||||
|
error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContChunck::read(void * buffer, unsigned int size) {
|
||||||
|
if(size <= 0 || (_curPos + size) > _size) error("invalid buffer read request");
|
||||||
|
memcpy(buffer, _data + _curPos, size);
|
||||||
|
_curPos += size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ContChunck::getChar() {
|
||||||
|
if(_curPos >= _size) error("invalid char read request");
|
||||||
|
return _data[_curPos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char ContChunck::getByte() {
|
||||||
|
if(_curPos >= _size) error("invalid byte read request");
|
||||||
|
unsigned char * ptr = (unsigned char *)(_data + _curPos);
|
||||||
|
_curPos += 1;
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
short ContChunck::getShort() {
|
||||||
|
if(_curPos >= _size - 1) error("invalid short read request");
|
||||||
|
unsigned short buffer = getWord();
|
||||||
|
return *((short*)&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short ContChunck::getWord() {
|
||||||
|
if(_curPos >= _size - 1) error("invalid word read request");
|
||||||
|
unsigned short * ptr = (unsigned short *)(_data + _curPos);
|
||||||
|
_curPos += 2;
|
||||||
|
return READ_LE_UINT16(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ContChunck::getDword() {
|
||||||
|
if(_curPos >= _size - 3) error("invalid dword read request");
|
||||||
|
unsigned int * ptr = (unsigned int *)(_data + _curPos);
|
||||||
|
_curPos += 4;
|
||||||
|
return READ_LE_UINT32(ptr);
|
||||||
|
}
|
121
scumm/smush/chunck.h
Normal file
121
scumm/smush/chunck.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CHUNCK_H_
|
||||||
|
#define __CHUNCK_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/*! @brief Interface for chunck handling
|
||||||
|
|
||||||
|
This class is an interface for reading from a chunck.
|
||||||
|
|
||||||
|
\todo handle big endian system.
|
||||||
|
*/
|
||||||
|
class Chunck {
|
||||||
|
public:
|
||||||
|
enum seek_type { seek_start, seek_end, seek_cur };
|
||||||
|
virtual ~Chunck() {};
|
||||||
|
typedef unsigned int type; //!< type of a chunck (i.e. The first 4byte field of the chunck structure).
|
||||||
|
/*! @brief convert a type to a string
|
||||||
|
|
||||||
|
Utility function that convert a type to a string.
|
||||||
|
|
||||||
|
@param t the type to convert to a string
|
||||||
|
|
||||||
|
@return the converted string
|
||||||
|
*/
|
||||||
|
static const char * ChunckString(type t);
|
||||||
|
|
||||||
|
virtual type getType() const = 0; //!< return the type of the chunck
|
||||||
|
virtual unsigned int getSize() const = 0; //!< return the size of the chunck
|
||||||
|
virtual Chunck * subBlock() = 0; //!< extract a subchunck from the current read position
|
||||||
|
virtual bool eof() const = 0; //!< is the chunck completely read ?
|
||||||
|
virtual unsigned int tell() const = 0; //!< get the chunck current read position
|
||||||
|
virtual bool seek(int delta, seek_type dir = seek_cur) = 0; //!< move the current read position inside the chunck
|
||||||
|
virtual bool read(void * buffer, unsigned int size) = 0; //!< read some data for the current read position
|
||||||
|
virtual char getChar() = 0; //!< extract the character at the current read position
|
||||||
|
virtual unsigned char getByte() = 0; //!< extract the byte at the current read position
|
||||||
|
virtual short getShort() = 0; //!< extract the short at the current read position
|
||||||
|
virtual unsigned short getWord() = 0; //!< extract the word at the current read position
|
||||||
|
virtual unsigned int getDword()= 0; //!< extract the dword at the current read position
|
||||||
|
};
|
||||||
|
|
||||||
|
class FilePtr;
|
||||||
|
|
||||||
|
/*! @brief file based ::chunck
|
||||||
|
|
||||||
|
This class is an implementation of ::chunck that handles file.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class FileChunck : public Chunck {
|
||||||
|
private:
|
||||||
|
FilePtr * _data;
|
||||||
|
type _type;
|
||||||
|
unsigned int _size;
|
||||||
|
unsigned int _offset;
|
||||||
|
unsigned int _curPos;
|
||||||
|
protected:
|
||||||
|
FileChunck();
|
||||||
|
public:
|
||||||
|
FileChunck(const char * fname);
|
||||||
|
virtual ~FileChunck();
|
||||||
|
type getType() const;
|
||||||
|
unsigned int getSize() const;
|
||||||
|
Chunck * subBlock();
|
||||||
|
bool eof() const;
|
||||||
|
unsigned int tell() const;
|
||||||
|
bool seek(int delta, seek_type dir = seek_cur);
|
||||||
|
bool read(void * buffer, unsigned int size);
|
||||||
|
char getChar();
|
||||||
|
unsigned char getByte();
|
||||||
|
short getShort();
|
||||||
|
unsigned short getWord();
|
||||||
|
unsigned int getDword();
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! @brief memory based ::chunck
|
||||||
|
|
||||||
|
This class is an implementation of ::chunck that handles a memory buffer.
|
||||||
|
*/
|
||||||
|
class ContChunck : public Chunck {
|
||||||
|
private:
|
||||||
|
char * _data;
|
||||||
|
Chunck::type _type;
|
||||||
|
unsigned int _size;
|
||||||
|
unsigned int _curPos;
|
||||||
|
public:
|
||||||
|
ContChunck(char * data);
|
||||||
|
Chunck::type getType() const;
|
||||||
|
unsigned int getSize() const;
|
||||||
|
Chunck * subBlock();
|
||||||
|
bool eof() const;
|
||||||
|
unsigned int tell() const;
|
||||||
|
bool seek(int delta, seek_type dir = seek_cur);
|
||||||
|
bool read(void * buffer, unsigned int size);
|
||||||
|
char getChar();
|
||||||
|
unsigned char getByte();
|
||||||
|
short getShort();
|
||||||
|
unsigned short getWord();
|
||||||
|
unsigned int getDword();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
57
scumm/smush/chunck_type.h
Normal file
57
scumm/smush/chunck_type.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CHUNCK_TYPE_H
|
||||||
|
#define __CHUNCK_TYPE_H
|
||||||
|
|
||||||
|
#include "chunck.h"
|
||||||
|
|
||||||
|
#define MAKE_TYPE(a,b,c,d) (Chunck::type)( ((a) << 24) | ((b) << 16) | ((c) << 8) | (d) )
|
||||||
|
|
||||||
|
static const Chunck::type TYPE_ANIM = MAKE_TYPE('A', 'N', 'I', 'M');
|
||||||
|
static const Chunck::type TYPE_AHDR = MAKE_TYPE('A', 'H', 'D', 'R');
|
||||||
|
static const Chunck::type TYPE_FRME = MAKE_TYPE('F', 'R', 'M', 'E');
|
||||||
|
static const Chunck::type TYPE_NPAL = MAKE_TYPE('N', 'P', 'A', 'L');
|
||||||
|
static const Chunck::type TYPE_FOBJ = MAKE_TYPE('F', 'O', 'B', 'J');
|
||||||
|
static const Chunck::type TYPE_PSAD = MAKE_TYPE('P', 'S', 'A', 'D');
|
||||||
|
static const Chunck::type TYPE_TRES = MAKE_TYPE('T', 'R', 'E', 'S');
|
||||||
|
static const Chunck::type TYPE_XPAL = MAKE_TYPE('X', 'P', 'A', 'L');
|
||||||
|
static const Chunck::type TYPE_IACT = MAKE_TYPE('I', 'A', 'C', 'T');
|
||||||
|
static const Chunck::type TYPE_STOR = MAKE_TYPE('S', 'T', 'O', 'R');
|
||||||
|
static const Chunck::type TYPE_FTCH = MAKE_TYPE('F', 'T', 'C', 'H');
|
||||||
|
static const Chunck::type TYPE_SKIP = MAKE_TYPE('S', 'K', 'I', 'P');
|
||||||
|
static const Chunck::type TYPE_STRK = MAKE_TYPE('S', 'T', 'R', 'K');
|
||||||
|
static const Chunck::type TYPE_SMRK = MAKE_TYPE('S', 'M', 'R', 'K');
|
||||||
|
static const Chunck::type TYPE_SHDR = MAKE_TYPE('S', 'H', 'D', 'R');
|
||||||
|
static const Chunck::type TYPE_SDAT = MAKE_TYPE('S', 'D', 'A', 'T');
|
||||||
|
static const Chunck::type TYPE_SAUD = MAKE_TYPE('S', 'A', 'U', 'D');
|
||||||
|
static const Chunck::type TYPE_iMUS = MAKE_TYPE('i', 'M', 'U', 'S');
|
||||||
|
static const Chunck::type TYPE_FRMT = MAKE_TYPE('F', 'R', 'M', 'T');
|
||||||
|
static const Chunck::type TYPE_TEXT = MAKE_TYPE('T', 'E', 'X', 'T');
|
||||||
|
static const Chunck::type TYPE_REGN = MAKE_TYPE('R', 'E', 'G', 'N');
|
||||||
|
static const Chunck::type TYPE_STOP = MAKE_TYPE('S', 'T', 'O', 'P');
|
||||||
|
static const Chunck::type TYPE_MAP_ = MAKE_TYPE('M', 'A', 'P', ' ');
|
||||||
|
static const Chunck::type TYPE_DATA = MAKE_TYPE('D', 'A', 'T', 'A');
|
||||||
|
static const Chunck::type TYPE_ETRS = MAKE_TYPE('E', 'T', 'R', 'S');
|
||||||
|
|
||||||
|
#undef MAKE_TYPE
|
||||||
|
|
||||||
|
#endif
|
76
scumm/smush/codec1.cpp
Normal file
76
scumm/smush/codec1.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "codec1.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
Codec1Decoder::~Codec1Decoder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Codec1Decoder::decode(Blitter & dst, Chunck & src) {
|
||||||
|
int val;
|
||||||
|
int size_line;
|
||||||
|
int code, length;
|
||||||
|
int h, height = getRect().height();
|
||||||
|
|
||||||
|
for(h = 0; h < height; h++) {
|
||||||
|
size_line = src.getWord(); // size of compressed line !
|
||||||
|
#ifdef DEBUG_CODEC1
|
||||||
|
debug(7, "codec1 : h == %d, size_line == %d", h, size_line);
|
||||||
|
#endif
|
||||||
|
while(size_line > 0) {
|
||||||
|
code = src.getByte();
|
||||||
|
size_line --;
|
||||||
|
length = (code >> 1) + 1;
|
||||||
|
#ifdef DEBUG_CODEC1
|
||||||
|
debug(7, "codec1 : length == %d", length);
|
||||||
|
#endif
|
||||||
|
if(code & 1) {
|
||||||
|
val = src.getByte();
|
||||||
|
size_line --;
|
||||||
|
if(val) dst.put(val, length);
|
||||||
|
else dst.advance(length);
|
||||||
|
#ifdef DEBUG_CODEC1
|
||||||
|
debug(7, "codec1 : blitting %d times %d", length, val);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
size_line -= length;
|
||||||
|
#ifdef DEBUG_CODEC1
|
||||||
|
debug(7, "codec1 : blitting %d entries", length);
|
||||||
|
#endif
|
||||||
|
while(length--) {
|
||||||
|
val = src.getByte();
|
||||||
|
if(val) dst.put(val);
|
||||||
|
else dst.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_CODEC1
|
||||||
|
if(!src.eof()) {
|
||||||
|
int len = src.getSize() - src.tell();
|
||||||
|
debug(7, "codec1: remaining length after decode == %d", len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
48
scumm/smush/codec1.h
Normal file
48
scumm/smush/codec1.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CODEC1_H_
|
||||||
|
#define __CODEC1_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_CODEC1
|
||||||
|
# define DEBUG_CODEC1
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_CODEC1
|
||||||
|
# error DEBUG_CODEC1 defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "decoder.h"
|
||||||
|
|
||||||
|
/*! @brief ::decoder for codec 1 and 3.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class Codec1Decoder : public Decoder {
|
||||||
|
public:
|
||||||
|
virtual ~Codec1Decoder();
|
||||||
|
bool decode(Blitter &, Chunck &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
436
scumm/smush/codec37.cpp
Normal file
436
scumm/smush/codec37.cpp
Normal file
|
@ -0,0 +1,436 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "codec37.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h> // for memset
|
||||||
|
|
||||||
|
bool Codec37Decoder::initSize(const Point & p, const Rect & r) {
|
||||||
|
if(r.width() != getRect().width() && r.height() != getRect().height()) {
|
||||||
|
if(
|
||||||
|
(r.width() != 320 || r.height() != 200) &&
|
||||||
|
(r.width() != 384 || r.height() != 242) &&
|
||||||
|
(r.width() != 640 || r.height() != 480)
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
Decoder::initSize(p, r);
|
||||||
|
clean();
|
||||||
|
int frame_size = getRect().width() * getRect().height();
|
||||||
|
_deltaSize = frame_size * 2 + DELTA_ADD * 4;
|
||||||
|
_deltaBuf = new unsigned char[_deltaSize];
|
||||||
|
if(_deltaBuf == 0) error("unable to allocate decoder buffer");
|
||||||
|
_deltaBufs[0] = _deltaBuf + DELTA_ADD;
|
||||||
|
_deltaBufs[1] = _deltaBuf + frame_size + DELTA_ADD * 3;
|
||||||
|
_offsetTable = new short[255];
|
||||||
|
if(_offsetTable == 0) error("unable to allocate decoder offset table");
|
||||||
|
_tableLastPitch = -1;
|
||||||
|
_tableLastIndex = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Codec37Decoder::Codec37Decoder() {
|
||||||
|
_deltaSize = 0;
|
||||||
|
_deltaBuf = 0;
|
||||||
|
_deltaBufs[0] = 0;
|
||||||
|
_deltaBufs[1] = 0;
|
||||||
|
_curtable = 0;
|
||||||
|
_offsetTable = 0;
|
||||||
|
_tableLastPitch = -1;
|
||||||
|
_tableLastIndex = -1;
|
||||||
|
_prevSeqNb = 32768; // Some invalid number
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::clean() {
|
||||||
|
if(_offsetTable) {
|
||||||
|
delete []_offsetTable;
|
||||||
|
_offsetTable = 0;
|
||||||
|
_tableLastPitch = -1;
|
||||||
|
_tableLastIndex = -1;
|
||||||
|
}
|
||||||
|
if(_deltaBuf) {
|
||||||
|
delete []_deltaBuf;
|
||||||
|
_deltaSize = 0;
|
||||||
|
_deltaBuf = 0;
|
||||||
|
_deltaBufs[0] = 0;
|
||||||
|
_deltaBufs[1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Codec37Decoder::~Codec37Decoder() {
|
||||||
|
clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::maketable(int pitch, int index) {
|
||||||
|
static const char maketable_bytes[] = {
|
||||||
|
0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0, 13, 0, 21, 0,
|
||||||
|
-1, 0, -2, 0, -3, 0, -5, 0, -8, 0, -13, 0, -17, 0, -21, 0,
|
||||||
|
0, 1, 1, 1, 2, 1, 3, 1, 5, 1, 8, 1, 13, 1, 21, 1,
|
||||||
|
-1, 1, -2, 1, -3, 1, -5, 1, -8, 1, -13, 1, -17, 1, -21, 1,
|
||||||
|
0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 8, 2, 13, 2, 21, 2,
|
||||||
|
-1, 2, -2, 2, -3, 2, -5, 2, -8, 2, -13, 2, -17, 2, -21, 2,
|
||||||
|
0, 3, 1, 3, 2, 3, 3, 3, 5, 3, 8, 3, 13, 3, 21, 3,
|
||||||
|
-1, 3, -2, 3, -3, 3, -5, 3, -8, 3, -13, 3, -17, 3, -21, 3,
|
||||||
|
0, 5, 1, 5, 2, 5, 3, 5, 5, 5, 8, 5, 13, 5, 21, 5,
|
||||||
|
-1, 5, -2, 5, -3, 5, -5, 5, -8, 5, -13, 5, -17, 5, -21, 5,
|
||||||
|
0, 8, 1, 8, 2, 8, 3, 8, 5, 8, 8, 8, 13, 8, 21, 8,
|
||||||
|
-1, 8, -2, 8, -3, 8, -5, 8, -8, 8, -13, 8, -17, 8, -21, 8,
|
||||||
|
0, 13, 1, 13, 2, 13, 3, 13, 5, 13, 8, 13, 13, 13, 21, 13,
|
||||||
|
-1, 13, -2, 13, -3, 13, -5, 13, -8, 13, -13, 13, -17, 13, -21, 13,
|
||||||
|
0, 21, 1, 21, 2, 21, 3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
|
||||||
|
-1, 21, -2, 21, -3, 21, -5, 21, -8, 21, -13, 21, -17, 21, -21, 21,
|
||||||
|
0, -1, 1, -1, 2, -1, 3, -1, 5, -1, 8, -1, 13, -1, 21, -1,
|
||||||
|
-1, -1, -2, -1, -3, -1, -5, -1, -8, -1, -13, -1, -17, -1, -21, -1,
|
||||||
|
0, -2, 1, -2, 2, -2, 3, -2, 5, -2, 8, -2, 13, -2, 21, -2,
|
||||||
|
-1, -2, -2, -2, -3, -2, -5, -2, -8, -2, -13, -2, -17, -2, -21, -2,
|
||||||
|
0, -3, 1, -3, 2, -3, 3, -3, 5, -3, 8, -3, 13, -3, 21, -3,
|
||||||
|
-1, -3, -2, -3, -3, -3, -5, -3, -8, -3, -13, -3, -17, -3, -21, -3,
|
||||||
|
0, -5, 1, -5, 2, -5, 3, -5, 5, -5, 8, -5, 13, -5, 21, -5,
|
||||||
|
-1, -5, -2, -5, -3, -5, -5, -5, -8, -5, -13, -5, -17, -5, -21, -5,
|
||||||
|
0, -8, 1, -8, 2, -8, 3, -8, 5, -8, 8, -8, 13, -8, 21, -8,
|
||||||
|
-1, -8, -2, -8, -3, -8, -5, -8, -8, -8, -13, -8, -17, -8, -21, -8,
|
||||||
|
0, -13, 1, -13, 2, -13, 3, -13, 5, -13, 8, -13, 13, -13, 21, -13,
|
||||||
|
-1, -13, -2, -13, -3, -13, -5, -13, -8, -13, -13, -13, -17, -13, -21, -13,
|
||||||
|
0, -17, 1, -17, 2, -17, 3, -17, 5, -17, 8, -17, 13, -17, 21, -17,
|
||||||
|
-1, -17, -2, -17, -3, -17, -5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
|
||||||
|
0, -21, 1, -21, 2, -21, 3, -21, 5, -21, 8, -21, 13, -21, 21, -21,
|
||||||
|
-1, -21, -2, -21, -3, -21, -5, -21, -8, -21, -13, -21, -17, -21, 0, 0,
|
||||||
|
-8, -29, 8, -29, -18, -25, 17, -25, 0, -23, -6, -22, 6, -22, -13, -19,
|
||||||
|
12, -19, 0, -18, 25, -18, -25, -17, -5, -17, 5, -17, -10, -15, 10, -15,
|
||||||
|
0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
|
||||||
|
2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9,
|
||||||
|
1, -9, 6, -9, -29, -8, -11, -8, -8, -8, -3, -8, 3, -8, 8, -8,
|
||||||
|
11, -8, 29, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6,
|
||||||
|
-9, -6, -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6,
|
||||||
|
22, -6, -17, -5, -7, -5, -4, -5, -2, -5, 0, -5, 2, -5, 4, -5,
|
||||||
|
7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -1, -4, 0, -4,
|
||||||
|
1, -4, 3, -4, 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, -4, -3,
|
||||||
|
-3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2, -3, 4, -3, 6, -3,
|
||||||
|
8, -3, -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, -1, -2, 0, -2,
|
||||||
|
1, -2, 2, -2, 3, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
|
||||||
|
-4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1,
|
||||||
|
4, -1, 6, -1, 9, -1, -31, 0, -23, 0, -18, 0, -14, 0, -11, 0,
|
||||||
|
-7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -31, 1, 0,
|
||||||
|
2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0,
|
||||||
|
23, 0, 31, 0, -9, 1, -6, 1, -4, 1, -3, 1, -2, 1, -1, 1,
|
||||||
|
0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 6, 1, 9, 1, -11, 2,
|
||||||
|
-7, 2, -5, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2,
|
||||||
|
3, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, -4, 3, -2, 3,
|
||||||
|
-1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 6, 3, 8, 3,
|
||||||
|
-13, 4, -10, 4, -5, 4, -3, 4, -1, 4, 0, 4, 1, 4, 3, 4,
|
||||||
|
5, 4, 10, 4, 13, 4, -17, 5, -7, 5, -4, 5, -2, 5, 0, 5,
|
||||||
|
2, 5, 4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6,
|
||||||
|
-1, 6, 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7,
|
||||||
|
0, 7, 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, -3, 8, 3, 8,
|
||||||
|
8, 8, 11, 8, 29, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
|
||||||
|
-4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
|
||||||
|
19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17,
|
||||||
|
5, 17, 25, 17, -25, 18, 0, 18, -12, 19, 13, 19, -6, 22, 6, 22,
|
||||||
|
0, 23, -17, 25, 18, 25, -8, 29, 8, 29, 0, 31, 0, 0, -6, -22,
|
||||||
|
6, -22, -13, -19, 12, -19, 0, -18, -5, -17, 5, -17, -10, -15, 10, -15,
|
||||||
|
0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
|
||||||
|
2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, -1, -9,
|
||||||
|
1, -9, 6, -9, -11, -8, -8, -8, -3, -8, 0, -8, 3, -8, 8, -8,
|
||||||
|
11, -8, -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, -22, -6, -9, -6,
|
||||||
|
-6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 6, -6, 9, -6, 22, -6,
|
||||||
|
-17, -5, -7, -5, -4, -5, -2, -5, -1, -5, 0, -5, 1, -5, 2, -5,
|
||||||
|
4, -5, 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -2, -4,
|
||||||
|
-1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 5, -4, 10, -4, 13, -4,
|
||||||
|
-8, -3, -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3,
|
||||||
|
2, -3, 3, -3, 4, -3, 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
|
||||||
|
-4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 3, -2,
|
||||||
|
4, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, -5, -1, -4, -1,
|
||||||
|
-3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
|
||||||
|
5, -1, 6, -1, 9, -1, -23, 0, -18, 0, -14, 0, -11, 0, -7, 0,
|
||||||
|
-5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, -23, 1, 0, 2, 0,
|
||||||
|
3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 14, 0, 18, 0, 23, 0,
|
||||||
|
-9, 1, -6, 1, -5, 1, -4, 1, -3, 1, -2, 1, -1, 1, 0, 1,
|
||||||
|
1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 9, 1, -11, 2,
|
||||||
|
-7, 2, -5, 2, -4, 2, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
|
||||||
|
2, 2, 3, 2, 4, 2, 5, 2, 7, 2, 11, 2, -8, 3, -6, 3,
|
||||||
|
-4, 3, -3, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3,
|
||||||
|
4, 3, 6, 3, 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, -2, 4,
|
||||||
|
-1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 5, 4, 10, 4, 13, 4,
|
||||||
|
-17, 5, -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 1, 5, 2, 5,
|
||||||
|
4, 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
|
||||||
|
1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
|
||||||
|
2, 7, 5, 7, -11, 8, -8, 8, -3, 8, 0, 8, 3, 8, 8, 8,
|
||||||
|
11, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, -4, 10, 4, 10,
|
||||||
|
15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11, 19, 12, -19, 13,
|
||||||
|
-4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5, 17, 5, 17, 0, 18,
|
||||||
|
-12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_tableLastPitch == pitch && _tableLastIndex == index)
|
||||||
|
return;
|
||||||
|
#ifdef DEBUG_CODEC37
|
||||||
|
debug(7, "codec37::maketable(%d, %d) called", pitch, index);
|
||||||
|
#endif
|
||||||
|
_tableLastPitch = pitch;
|
||||||
|
_tableLastIndex = index;
|
||||||
|
index *= 255;
|
||||||
|
assert(index + 254 < (int)(sizeof(maketable_bytes) / 2));
|
||||||
|
|
||||||
|
for (int i = 0; i < 255; i++) {
|
||||||
|
int j = (i + index) << 1; // * 2
|
||||||
|
_offsetTable[i] = maketable_bytes[j + 1] * pitch + maketable_bytes[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::proc1(Blitter & dst, Chunck & src, int next_offs, int bw, int bh, int size) {
|
||||||
|
unsigned char * decoded = new unsigned char[size];
|
||||||
|
int w = 0;
|
||||||
|
while(!src.eof()) {
|
||||||
|
int code = src.getByte();
|
||||||
|
int length = (code >> 1) + 1;
|
||||||
|
if (code & 1) {
|
||||||
|
unsigned char val = src.getByte();
|
||||||
|
while(length--)
|
||||||
|
decoded[w++] = val;
|
||||||
|
} else {
|
||||||
|
while(length--) {
|
||||||
|
decoded[w++] = src.getByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(w == size);
|
||||||
|
w = 0;
|
||||||
|
// Now we have our stream ready...
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
if(decoded[i] == 0xFF) {
|
||||||
|
dst.putBlock(decoded + i + 1);
|
||||||
|
i += 16;
|
||||||
|
} else {
|
||||||
|
dst.blockCopy(_offsetTable[decoded[i]] + next_offs);
|
||||||
|
}
|
||||||
|
if(++w == bw) {
|
||||||
|
w = 0;
|
||||||
|
dst.advance(0, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete []decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::proc2(Blitter & dst, Chunck & src, int size) { // This is codec1 like...
|
||||||
|
#ifdef DEBUG_CODEC37_PROC2
|
||||||
|
int decoded_size = 0;
|
||||||
|
int coded_size = 0;
|
||||||
|
#endif
|
||||||
|
do {
|
||||||
|
int code = src.getByte();
|
||||||
|
int length = (code >> 1) + 1;
|
||||||
|
size -= length;
|
||||||
|
#ifdef DEBUG_CODEC37_PROC2
|
||||||
|
decoded_size += length;
|
||||||
|
coded_size += 1 + ((code & 1) ? 1 : length);
|
||||||
|
|
||||||
|
debug(7, "proc2() : code == %d : length == %d : decoded_size == %d : coded_size == %d : seek - header == %d : size == %d",
|
||||||
|
code, length, decoded_size, coded_size, src.tell() - 31, size + decoded_size);
|
||||||
|
#endif
|
||||||
|
if (code & 1)
|
||||||
|
dst.put(src.getChar(), length);
|
||||||
|
else
|
||||||
|
// while(length--) dst.put(src.get_char());
|
||||||
|
dst.blit(src, length);
|
||||||
|
} while (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::proc3WithFDFE(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) {
|
||||||
|
do {
|
||||||
|
int i = bw;
|
||||||
|
do {
|
||||||
|
int code = src.getByte();
|
||||||
|
if (code == 0xFD) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(1));
|
||||||
|
#else
|
||||||
|
dst.putBlock(expand(src.getByte()));
|
||||||
|
#endif
|
||||||
|
} else if (code == 0xFE) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(2));
|
||||||
|
#else
|
||||||
|
dst.putBlock(expand(src.getByte()), expand(src.getByte()), expand(src.getByte()), expand(src.getByte()));
|
||||||
|
#endif
|
||||||
|
} else if (code == 0xFF) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(3));
|
||||||
|
#else
|
||||||
|
dst.putBlock(src);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(4));
|
||||||
|
#else
|
||||||
|
dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset !
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} while (--i);
|
||||||
|
dst.advance(0, 3); // advance 3 lines
|
||||||
|
} while (--bh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::proc3WithoutFDFE(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) {
|
||||||
|
do {
|
||||||
|
int i = bw;
|
||||||
|
do {
|
||||||
|
int code = src.getByte();
|
||||||
|
if (code == 0xFF) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(5));
|
||||||
|
#else
|
||||||
|
dst.putBlock(src);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(6));
|
||||||
|
#else
|
||||||
|
dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset !
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} while (--i);
|
||||||
|
dst.advance(0, 3); // advance 3 lines
|
||||||
|
} while (--bh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Codec37Decoder::proc4(Blitter & dst, Chunck & src, int next_offs, int bw, int bh) {
|
||||||
|
#ifdef DEBUG_CODEC37_PROC4
|
||||||
|
int b_nb = 0;
|
||||||
|
#endif
|
||||||
|
do {
|
||||||
|
int i = bw;
|
||||||
|
do {
|
||||||
|
int code = src.getByte();
|
||||||
|
if (code == 0xFD) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(7));
|
||||||
|
#else
|
||||||
|
dst.putBlock(expand(src.getByte()));
|
||||||
|
#endif
|
||||||
|
} else if (code == 0xFE) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(8));
|
||||||
|
#else
|
||||||
|
dst.putBlock(expand(src.getByte()), expand(src.getByte()), expand(src.getByte()), expand(src.getByte()));
|
||||||
|
#endif
|
||||||
|
} else if (code == 0xFF) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(9));
|
||||||
|
#else
|
||||||
|
dst.putBlock(src);
|
||||||
|
#endif
|
||||||
|
} else if (code == 0x00) {
|
||||||
|
int length = src.getByte() + 1;
|
||||||
|
for (int l = 0; l < length; l++) {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(10));
|
||||||
|
#else
|
||||||
|
dst.blockCopy(next_offs);
|
||||||
|
#endif
|
||||||
|
i--;
|
||||||
|
if (i == 0) {
|
||||||
|
dst.advance(0, 3); // advance 3 lines
|
||||||
|
bh--;
|
||||||
|
i = bw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bh == 0) return;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
#ifdef USE_COLOR_CODE_FOR_BLOCK
|
||||||
|
dst.putBlock(expand(11));
|
||||||
|
#else
|
||||||
|
dst.blockCopy(_offsetTable[code] + next_offs); // copy from an offset !
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} while (--i);
|
||||||
|
dst.advance(0, 3); // advance 3 lines
|
||||||
|
} while (--bh);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Codec37Decoder::decode(Blitter & dst, Chunck & src) {
|
||||||
|
int width = getRect().width();
|
||||||
|
int height = getRect().height();
|
||||||
|
int bw = (width + 3) >> 2, bh = (height + 3) >> 2;
|
||||||
|
int pitch = bw << 2;
|
||||||
|
#ifdef DEBUG_CODEC37
|
||||||
|
debug(7, "codec37::decode() : width == %d : height == %d : pitch == %d : _prevSeqNb == %d",
|
||||||
|
width, height, pitch, _prevSeqNb);
|
||||||
|
#endif
|
||||||
|
int code = src.getByte(); // 0 -> 1 (1)
|
||||||
|
int index = src.getByte(); // 1 -> 2 (1)
|
||||||
|
unsigned short seq_nb = src.getWord(); // 2 -> 4 (2)
|
||||||
|
unsigned int decoded_size = src.getDword(); // 4 -> 8 (4)
|
||||||
|
#ifdef DEBUG_CODEC37
|
||||||
|
unsigned int coded_size = src.getDword(); // 8 -> 12 (4)
|
||||||
|
#else
|
||||||
|
src.seek(4);
|
||||||
|
#endif
|
||||||
|
unsigned int mask_flag = src.getDword(); // 12 -> 16 (4)
|
||||||
|
#ifdef DEBUG_CODEC37
|
||||||
|
debug(7, "codec37::decode() : code == %d : index == %d : seq_nb == %d : decoded_size == %d : coded_size == %d : mask_flag == %d",
|
||||||
|
code, index, seq_nb, decoded_size, coded_size, mask_flag);
|
||||||
|
#endif
|
||||||
|
maketable(pitch, index);
|
||||||
|
if(code == 3 || code == 4 || code == 1) {
|
||||||
|
assert(seq_nb && _prevSeqNb + 1 == seq_nb);
|
||||||
|
if (seq_nb & 1 || !(mask_flag & 1)) _curtable ^= 1;
|
||||||
|
}
|
||||||
|
Blitter blit((char *)_deltaBufs[_curtable], Point(width, height), Rect(0, 0, width, height));
|
||||||
|
switch(code) {
|
||||||
|
case 0:
|
||||||
|
memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf);
|
||||||
|
memset(_deltaBufs[_curtable] + decoded_size, 0, _deltaBuf + _deltaSize - _deltaBufs[_curtable] - decoded_size);
|
||||||
|
blit.blit(src, decoded_size);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
proc1(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh, decoded_size);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
memset(_deltaBuf, 0, _deltaBufs[_curtable] - _deltaBuf);
|
||||||
|
memset(_deltaBufs[_curtable] + decoded_size, 0, _deltaBuf + _deltaSize - _deltaBufs[_curtable] - decoded_size);
|
||||||
|
proc2(blit, src, decoded_size);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if(mask_flag & 1)
|
||||||
|
proc3WithFDFE(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh);
|
||||||
|
else
|
||||||
|
proc3WithoutFDFE(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
proc4(blit, src, _deltaBufs[_curtable ^ 1] - _deltaBufs[_curtable], bw, bh);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef DEBUG_CODEC37
|
||||||
|
error("codec37::decode() received an invalid code : %d", code);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dst.blit((char*)_deltaBufs[_curtable], width * height);
|
||||||
|
_prevSeqNb = seq_nb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
86
scumm/smush/codec37.h
Normal file
86
scumm/smush/codec37.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CODEC37_H_
|
||||||
|
#define __CODEC37_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_CODEC37
|
||||||
|
# define DEBUG_CODEC37
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_CODEC37
|
||||||
|
# error DEBUG_CODEC37 defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_CODEC37
|
||||||
|
# ifndef NO_DEBUG_CODEC37_PROCS
|
||||||
|
# define DEBUG_CODEC37_PROC1
|
||||||
|
# define DEBUG_CODEC37_PROC2
|
||||||
|
# define DEBUG_CODEC37_PROC3
|
||||||
|
# define DEBUG_CODEC37_PROC4
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "decoder.h"
|
||||||
|
|
||||||
|
/*! @brief ::decoder for codec 37.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DELTA_ADD 0x3E00 // what is this 0x3E00 ?? == 320*200/4 - 128
|
||||||
|
// It looks like it is a safe-guarding protection from bugs., but maybe not...
|
||||||
|
|
||||||
|
class Codec37Decoder : public Decoder {
|
||||||
|
private:
|
||||||
|
int _deltaSize;
|
||||||
|
unsigned char * _deltaBufs[2];
|
||||||
|
unsigned char * _deltaBuf;
|
||||||
|
short * _offsetTable;
|
||||||
|
int _curtable;
|
||||||
|
unsigned short _prevSeqNb;
|
||||||
|
int _tableLastPitch;
|
||||||
|
int _tableLastIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool initSize(const Point &, const Rect &);
|
||||||
|
Codec37Decoder();
|
||||||
|
void clean();
|
||||||
|
virtual ~Codec37Decoder();
|
||||||
|
protected:
|
||||||
|
static inline unsigned int expand(unsigned char b) {
|
||||||
|
unsigned int r = b | (b << 8);
|
||||||
|
return r | (r << 16);
|
||||||
|
}
|
||||||
|
void maketable(int, int);
|
||||||
|
void proc1(Blitter &, Chunck &, int, int, int, int);
|
||||||
|
void proc2(Blitter &, Chunck &, int);
|
||||||
|
void proc3WithFDFE(Blitter &, Chunck &, int, int, int);
|
||||||
|
void proc3WithoutFDFE(Blitter &, Chunck &, int, int, int);
|
||||||
|
void proc4(Blitter &, Chunck &, int, int, int);
|
||||||
|
public:
|
||||||
|
bool decode(Blitter &, Chunck &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
71
scumm/smush/codec44.cpp
Normal file
71
scumm/smush/codec44.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "codec44.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
bool Codec44Decoder::decode(Blitter & dst, Chunck & src) {
|
||||||
|
int size_line;
|
||||||
|
int num;
|
||||||
|
int w, width = getRect().width() + 1;
|
||||||
|
int h, height = getRect().height() + 1;
|
||||||
|
bool zero;
|
||||||
|
#ifdef DEBUG_CODEC44
|
||||||
|
debug(7, "codec44 : %dx%d", width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(h = 0; h < height - 1; h++) {
|
||||||
|
w = width;
|
||||||
|
size_line = src.getWord(); // size of compressed line !
|
||||||
|
#ifdef DEBUG_CODEC44
|
||||||
|
debug(7, "codec44 : h == %d, size_line == %d", h, size_line);
|
||||||
|
#endif
|
||||||
|
zero = true;
|
||||||
|
while(size_line > 1) {
|
||||||
|
num = src.getWord();
|
||||||
|
size_line -= 2;
|
||||||
|
if(zero) {
|
||||||
|
#ifdef DEBUG_CODEC44
|
||||||
|
debug(7, "codec44 : zeroing %d, entries", num);
|
||||||
|
#endif
|
||||||
|
if(w == num)
|
||||||
|
num--;
|
||||||
|
w -= num;
|
||||||
|
if(num)
|
||||||
|
dst.put(0, num);
|
||||||
|
} else {
|
||||||
|
num += 1;
|
||||||
|
#ifdef DEBUG_CODEC44
|
||||||
|
debug(7, "codec44 : blitting %d, entries", num);
|
||||||
|
#endif
|
||||||
|
if(w == num)
|
||||||
|
num--;
|
||||||
|
w -= num;
|
||||||
|
dst.blit(src, num);
|
||||||
|
size_line -= num;
|
||||||
|
}
|
||||||
|
zero = !zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
47
scumm/smush/codec44.h
Normal file
47
scumm/smush/codec44.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CODEC44_H_
|
||||||
|
#define __CODEC44_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_CODEC44
|
||||||
|
# define DEBUG_CODEC44
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_CODEC44
|
||||||
|
# error DEBUG_CODEC44 defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "decoder.h"
|
||||||
|
|
||||||
|
/*! @brief ::decoder for codec 21 and 44.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class Codec44Decoder : public Decoder {
|
||||||
|
public:
|
||||||
|
bool decode(Blitter & dst, Chunck & src);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
51
scumm/smush/codec47.cpp
Normal file
51
scumm/smush/codec47.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "codec47.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
DumpDecoder::~DumpDecoder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DumpDecoder::decode(Blitter & dst, Chunck & src) {
|
||||||
|
int n = 0, i = 0;
|
||||||
|
int seq = src.getWord();
|
||||||
|
int codec = src.getByte();
|
||||||
|
int flags = src.getByte();
|
||||||
|
int unknown[22];
|
||||||
|
for(i = 0; i < 0; i++) {
|
||||||
|
unknown[i] = src.getByte();
|
||||||
|
}
|
||||||
|
if(codec == 5 || codec == 1) {
|
||||||
|
do {
|
||||||
|
int code = src.getByte();
|
||||||
|
int length = (code >> 1) + 1;
|
||||||
|
if (code & 1)
|
||||||
|
dst.put(src.getChar(), length);
|
||||||
|
else
|
||||||
|
dst.blit(src, length);
|
||||||
|
} while (!src.eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
38
scumm/smush/codec47.h
Normal file
38
scumm/smush/codec47.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CODEC_47_H_
|
||||||
|
#define __CODEC_47_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "decoder.h"
|
||||||
|
|
||||||
|
/*! @brief ::decoder for debugging purpose.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class DumpDecoder : public Decoder {
|
||||||
|
public:
|
||||||
|
virtual ~DumpDecoder();
|
||||||
|
bool decode(Blitter &, Chunck &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
69
scumm/smush/color.cpp
Normal file
69
scumm/smush/color.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "color.h"
|
||||||
|
|
||||||
|
Color::Color() : _r(0), _g(0), _b(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Color::Color(value_type r, value_type g, value_type b) : _r(r), _g(g), _b(b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Color::Color(const Color & c) : _r(c._r), _g(c._g), _b(c._b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Color & Color::operator=(const Color & c) {
|
||||||
|
_r = c._r;
|
||||||
|
_g = c._g;
|
||||||
|
_b = c._b;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color::~Color() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Color::value_type Color::red() const {
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color::value_type Color::green() const {
|
||||||
|
return _g;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color::value_type Color::blue() const {
|
||||||
|
return _b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Color::delta(short * ptr) {
|
||||||
|
// This is a very specific method for XPALs.
|
||||||
|
int t;
|
||||||
|
#define UPDATE_COLOR(c, inc) (((int)((c)) << 7) + (c) + (inc)) >> 7
|
||||||
|
#define CHECK_BOUNDS(c) (((c) > 255) ? 255 : (((c) < 0) ? 0 : (c)))
|
||||||
|
t = UPDATE_COLOR(_r, ptr[0]);
|
||||||
|
_r = CHECK_BOUNDS(t);
|
||||||
|
t = UPDATE_COLOR(_g, ptr[1]);
|
||||||
|
_g = CHECK_BOUNDS(t);
|
||||||
|
t = UPDATE_COLOR(_b, ptr[2]);
|
||||||
|
_b = CHECK_BOUNDS(t);
|
||||||
|
#undef UPDATE_COLOR
|
||||||
|
#undef CHECK_BOUNDS
|
||||||
|
}
|
57
scumm/smush/color.h
Normal file
57
scumm/smush/color.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COLOR_H_
|
||||||
|
#define __COLOR_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/*! @brief simple class for handling a color.
|
||||||
|
|
||||||
|
This small class is an helper for colors.
|
||||||
|
*/
|
||||||
|
class Color {
|
||||||
|
public:
|
||||||
|
typedef unsigned char value_type; //!< The type of the color components.
|
||||||
|
private:
|
||||||
|
value_type _r; //!< The red component.
|
||||||
|
value_type _g; //!< The green component.
|
||||||
|
value_type _b; //!< The blue component.
|
||||||
|
public:
|
||||||
|
Color();
|
||||||
|
Color(value_type, value_type, value_type);
|
||||||
|
Color(const Color &);
|
||||||
|
Color & operator=(const Color &);
|
||||||
|
virtual ~Color();
|
||||||
|
value_type red() const;
|
||||||
|
value_type green() const;
|
||||||
|
value_type blue() const;
|
||||||
|
/*! @brief handle delta palette modification
|
||||||
|
|
||||||
|
This method is used specifically by player::handleDeltaPalette().
|
||||||
|
It updates the color component using delta values given as short.
|
||||||
|
|
||||||
|
@param ptr pointer to a table of 3 shorts that contain delta values to use.
|
||||||
|
*/
|
||||||
|
void delta(short * ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
42
scumm/smush/config.h
Normal file
42
scumm/smush/config.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CONFIG_H_
|
||||||
|
#define __CONFIG_H_
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include <scumm.h>
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//~ #define NO_DEBUG_MIXER
|
||||||
|
//~ #define NO_DEBUG_CHANNEL
|
||||||
|
//~ #define NO_DEBUG_CLIPPER
|
||||||
|
#define NO_DEBUG_CODEC1
|
||||||
|
#define NO_DEBUG_CODEC37
|
||||||
|
#define NO_DEBUG_CODEC44
|
||||||
|
//~ #define NO_DEBUG_WIN32
|
||||||
|
//~ #define NO_DEBUG_FONT_RENDERER
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
51
scumm/smush/decoder.h
Normal file
51
scumm/smush/decoder.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DECODER_H_
|
||||||
|
#define __DECODER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
class Blitter;
|
||||||
|
class Chunck;
|
||||||
|
|
||||||
|
/*! @brief base class for codec decompression.
|
||||||
|
|
||||||
|
This class provides an interface for codec decompression.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class Decoder {
|
||||||
|
private:
|
||||||
|
Rect _r; //!< current size of the frame object to decode
|
||||||
|
Point _p; //!< position of the frame object to decode
|
||||||
|
protected:
|
||||||
|
const Rect & getRect() const{ return _r; }
|
||||||
|
const Point & getSize() const { return _p; }
|
||||||
|
public:
|
||||||
|
Decoder() {};
|
||||||
|
virtual ~Decoder() {};
|
||||||
|
virtual bool initSize(const Point & p, const Rect & r) { _p = p; _r = r; return true; };
|
||||||
|
virtual bool decode(Blitter &, Chunck &) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
232
scumm/smush/frenderer.cpp
Normal file
232
scumm/smush/frenderer.cpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "frenderer.h"
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h> // for memcpy, strcat, strdup
|
||||||
|
|
||||||
|
#ifndef max
|
||||||
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FontRenderer::FontRenderer(bool use_original_colors) : _nbChars(0), _color(-1), _original(use_original_colors) {
|
||||||
|
}
|
||||||
|
|
||||||
|
FontRenderer::~FontRenderer() {
|
||||||
|
for(int i = 0; i < _nbChars; i++) {
|
||||||
|
if(_chars[i].chr) delete []_chars[i].chr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontRenderer::save(int frame) {
|
||||||
|
_chars[_nbChars].width = getWidth();
|
||||||
|
_chars[_nbChars].height = getHeight();
|
||||||
|
int size = getWidth() * getHeight();
|
||||||
|
_chars[_nbChars].chr = new char[size];
|
||||||
|
memcpy(_chars[_nbChars].chr, data(), size);
|
||||||
|
_nbChars++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FontRenderer::charWidth(int v) const {
|
||||||
|
if(v < 0) v = 256 + v;
|
||||||
|
if(v < 0 || v >= _nbChars) error("invalid character in FontRenderer::charWidth : %d (%d)", v, _nbChars);
|
||||||
|
return _chars[v].width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FontRenderer::charHeight(int v) const {
|
||||||
|
if(v < 0) v = 256 + v;
|
||||||
|
if(v < 0 || v >= _nbChars) error("invalid character in FontRenderer::charHeight : %d (%d)", v, _nbChars);
|
||||||
|
return _chars[v].height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FontRenderer::stringWidth(const char * str) const {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
while(*str) {
|
||||||
|
ret += charWidth(*str++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FontRenderer::stringHeight(const char * str) const {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for(int i = 0; str[i] != 0; i++) {
|
||||||
|
int h = charHeight(str[i]);
|
||||||
|
ret = max(ret, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FontRenderer::drawChar(char * buffer, const Point & size, int x, int y, int chr) const {
|
||||||
|
int w = _chars[chr].width;
|
||||||
|
int h = _chars[chr].height;
|
||||||
|
char * src = _chars[chr].chr;
|
||||||
|
char * dst = buffer + size.getX() * y + x;
|
||||||
|
|
||||||
|
if(_original) {
|
||||||
|
for(int j = 0; j < h; j++) {
|
||||||
|
for(int i = 0; i < w; i++) {
|
||||||
|
int value = *src++;
|
||||||
|
if(value) dst[i] = value;
|
||||||
|
}
|
||||||
|
dst += size.getX();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int color = (_color != -1) ? _color : 1;
|
||||||
|
for(int j = 0; j < h; j++) {
|
||||||
|
for(int i = 0; i < w; i++) {
|
||||||
|
int value = *src++;
|
||||||
|
if(value == 1) {
|
||||||
|
dst[i] = color;
|
||||||
|
} else if(value) {
|
||||||
|
dst[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst += size.getX();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * * split(const char * str, char sep) {
|
||||||
|
char * * ret = new char *[32];
|
||||||
|
int n = 0;
|
||||||
|
const char * i = str, * j = strchr(i, sep);
|
||||||
|
|
||||||
|
while(j != NULL) {
|
||||||
|
assert(n < 30);
|
||||||
|
ret[n] = new char[j - i + 1];
|
||||||
|
memcpy(ret[n], i, j - i);
|
||||||
|
ret[n++][j - i] = 0;
|
||||||
|
i = j+1;
|
||||||
|
j = strchr(i, sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[n] = new char[strlen(i) + 1];
|
||||||
|
memcpy(ret[n], i, strlen(i));
|
||||||
|
ret[n++][strlen(i)] = 0;
|
||||||
|
ret[n] = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontRenderer::drawSubstring(const unsigned char * str, char * buffer, const Point & size, int x, int y) const {
|
||||||
|
for(int i = 0; str[i] != 0; i++)
|
||||||
|
x += drawChar(buffer, size, x, y, str[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontRenderer::drawStringAbsolute(const char * str, char * buffer, const Point & size, int x, int y) const {
|
||||||
|
debug(9, "FontRenderer::drawStringAbsolute(%s, %d, %d)", str, x, y);
|
||||||
|
while(str) {
|
||||||
|
char line[256];
|
||||||
|
char * pos = strchr(str, '\n');
|
||||||
|
if(pos) {
|
||||||
|
memcpy(line, str, pos - str - 1);
|
||||||
|
line[pos - str - 1] = 0;
|
||||||
|
str = pos + 1;
|
||||||
|
} else {
|
||||||
|
strcpy(line, str);
|
||||||
|
str = 0;
|
||||||
|
}
|
||||||
|
drawSubstring((const unsigned char *)line, buffer, size, x, y);
|
||||||
|
y += stringHeight(line);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontRenderer::drawStringCentered(const char * str, char * buffer, const Point & size, int y, int xmin, int width, int offset) const {
|
||||||
|
debug(9, "FontRenderer::drawStringCentered(%s, %d, %d)", str, xmin, y);
|
||||||
|
assert(strchr(str, '\n') == 0);
|
||||||
|
char * * words = split(str, ' ');
|
||||||
|
int nb_sub = 0;
|
||||||
|
|
||||||
|
while(words[nb_sub]) nb_sub++;
|
||||||
|
|
||||||
|
int * sizes = new int[nb_sub];
|
||||||
|
int i = 0, max_width = 0, height = 0, nb_subs = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < nb_sub; i++)
|
||||||
|
sizes[i] = stringWidth(words[i]);
|
||||||
|
|
||||||
|
char * * substrings = new char *[nb_sub];
|
||||||
|
int * substr_widths = new int[nb_sub];
|
||||||
|
int space_width = charWidth(' ');
|
||||||
|
|
||||||
|
while(i < nb_sub) {
|
||||||
|
int substr_width = sizes[i];
|
||||||
|
char * substr = new char[1000];
|
||||||
|
strcpy(substr, words[i]);
|
||||||
|
int j = i + 1;
|
||||||
|
|
||||||
|
while(j < nb_sub && (substr_width + space_width + sizes[j]) < width) {
|
||||||
|
substr_width += sizes[j++] + space_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int k = i + 1; k < j; k++) {
|
||||||
|
strcat(substr, " ");
|
||||||
|
strcat(substr, words[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
substrings[nb_subs] = substr;
|
||||||
|
substr_widths[nb_subs++] = substr_width;
|
||||||
|
if(substr_width > max_width)
|
||||||
|
max_width = substr_width;
|
||||||
|
i = j;
|
||||||
|
height += stringHeight(substr);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete []sizes;
|
||||||
|
for(i = 0; i < nb_sub; i++) {
|
||||||
|
delete []words[i];
|
||||||
|
}
|
||||||
|
delete []words;
|
||||||
|
|
||||||
|
max_width = (max_width + 1) >> 1;
|
||||||
|
// we have a box from 0 -> max_width
|
||||||
|
// we want a box from (xmin + offset) - max_width / 2, (xmin + offset) + max_width / 2
|
||||||
|
int x = xmin + width / 2;
|
||||||
|
x += offset - size.getX() / 2;
|
||||||
|
|
||||||
|
if(x < max_width) x = max_width;
|
||||||
|
if(x + max_width > size.getX()) {
|
||||||
|
x = size.getX() - max_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(y + height > size.getY()) {
|
||||||
|
y = size.getY() - height;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < nb_subs; i++) {
|
||||||
|
int substr_width = substr_widths[i];
|
||||||
|
drawSubstring((const unsigned char *)substrings[i], buffer, size, x - substr_width / 2, y);
|
||||||
|
y += stringHeight(substrings[i]);
|
||||||
|
delete []substrings[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete []substr_widths;
|
||||||
|
delete []substrings;
|
||||||
|
return true;
|
||||||
|
}
|
164
scumm/smush/frenderer.h
Normal file
164
scumm/smush/frenderer.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FRENDERER_H_
|
||||||
|
#define __FRENDERER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_FONT_RENDERER
|
||||||
|
# define DEBUG_FONT_RENDERER
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_FONT_RENDERER
|
||||||
|
# error DEBUG_FONT_RENDERER defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "brenderer.h"
|
||||||
|
#include "rect.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
/*! @brief ::renderer implementation specifically designed for font files.
|
||||||
|
|
||||||
|
This class is a valid ::renderer implementation. The frames are kept in memory, as bitmap representing characters, so that
|
||||||
|
they can be rendered again in another frame as strings.
|
||||||
|
|
||||||
|
This class also contains some functions useful for printing strings. This is used to show subtitles and more generally texts
|
||||||
|
in animations.
|
||||||
|
|
||||||
|
@todo update the mehod to use the ::blitter class, instead of direct pointers.
|
||||||
|
*/
|
||||||
|
class FontRenderer : public BaseRenderer {
|
||||||
|
private:
|
||||||
|
int _nbChars; //!< The number of frames in the font
|
||||||
|
int _color; //!< A color parameter used for font printing.
|
||||||
|
bool _original; //!< flag for color selection
|
||||||
|
struct {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
char * chr;
|
||||||
|
} _chars[256]; //!< array that contains the size of the different frames (i.e. characters) of the font.
|
||||||
|
public:
|
||||||
|
/*! @brief font_renderer constructor
|
||||||
|
|
||||||
|
@param use_original_colors flag to indicate if the font use it's own color, or if the base color are set at runtime.
|
||||||
|
*/
|
||||||
|
FontRenderer(bool use_original_colors = false);
|
||||||
|
virtual ~FontRenderer();
|
||||||
|
virtual bool wait(int ms) { return true; };
|
||||||
|
protected:
|
||||||
|
virtual void save(int frame = -1);
|
||||||
|
/*! @brief get the width of a character.
|
||||||
|
|
||||||
|
@param c the character we want the width from.
|
||||||
|
|
||||||
|
@return the width of the character
|
||||||
|
*/
|
||||||
|
int charWidth(int c) const;
|
||||||
|
/*! @brief get the width of a string.
|
||||||
|
|
||||||
|
@param str the string we want the width from.
|
||||||
|
|
||||||
|
@return the complete width of the string
|
||||||
|
*/
|
||||||
|
int stringWidth(const char * str) const;
|
||||||
|
/*! @brief get the height of a character.
|
||||||
|
|
||||||
|
@param c the character we want the height from.
|
||||||
|
|
||||||
|
@return the height of the character
|
||||||
|
*/
|
||||||
|
int charHeight(int c) const;
|
||||||
|
/*! @brief get the height of a string.
|
||||||
|
|
||||||
|
@param str the string we want the height from.
|
||||||
|
|
||||||
|
@return the complete height of the string
|
||||||
|
*/
|
||||||
|
int stringHeight(const char * str) const;
|
||||||
|
/*! @brief draw a character in the given frame buffer.
|
||||||
|
|
||||||
|
@param buffer the frame buffer to draw into.
|
||||||
|
@param size the size of the frame buffer.
|
||||||
|
@param x the horizontal position of the topleft corner of the character.
|
||||||
|
@param y the vertical position of the topleft corner of the character.
|
||||||
|
@param c the character to draw.
|
||||||
|
|
||||||
|
@bug This method does not clip. This is not really a bug, as it should always be correctly called, but some asserts would be welcome.
|
||||||
|
|
||||||
|
@return the width of the character
|
||||||
|
*/
|
||||||
|
int drawChar(char * buffer, const Point & size, int x, int y, int c) const;
|
||||||
|
/*! @brief draw a string in the given frame buffer.
|
||||||
|
|
||||||
|
@param str the string to draw.
|
||||||
|
@param buffer the frame buffer to draw into.
|
||||||
|
@param size the size of the frame buffer.
|
||||||
|
@param x the horizontal position of the topleft corner of the string.
|
||||||
|
@param y the vertical position of the topleft corner of the string.
|
||||||
|
|
||||||
|
@bug This method does not clip. This is not really a bug, as it should always be correctly called, but some asserts would be welcome.
|
||||||
|
*/
|
||||||
|
void drawSubstring(const unsigned char * str, char * buffer, const Point & size, int x, int y) const;
|
||||||
|
public:
|
||||||
|
/*! @brief change the programmable color of the font.
|
||||||
|
|
||||||
|
@param c the new color to use.
|
||||||
|
|
||||||
|
@return \c true if everything went fine, \c false otherwise
|
||||||
|
*/
|
||||||
|
bool setColor(int c) { _color = c; return true; }
|
||||||
|
/*! @brief draw a centered and possibly using multiple lines string.
|
||||||
|
|
||||||
|
This method performs calculation of the string size before choosing where to draw it.
|
||||||
|
As I still not have figured out exactly what is the meaning of the fields in the TRES chunck,
|
||||||
|
the real meaning of the parameters can be quite difficult to understand.
|
||||||
|
|
||||||
|
@remark The current implementation is incorrect in the sense that it does not conform to the original game.
|
||||||
|
@todo rewrite and rethink this to better match the original implementation.
|
||||||
|
|
||||||
|
@param str the string to draw.
|
||||||
|
@param buffer the frame buffer to draw into.
|
||||||
|
@param size the size of the frame buffer.
|
||||||
|
@param y the vertical position of the topleft corner of the string. This position may be changed if it is too low to be correctly drawn.
|
||||||
|
@param xmin the minimum horizontal position of the topleft corner of the string.
|
||||||
|
@param width the maximum width of the string. If the string is too long, it will wrap.
|
||||||
|
@param offset offset to give to the horizontal position.
|
||||||
|
|
||||||
|
@return \c true if everything went fine, \c false otherwise
|
||||||
|
*/
|
||||||
|
bool drawStringCentered(const char * str, char * buffer, const Point & size, int y, int xmin, int width, int offset) const;
|
||||||
|
/*! @brief draw a string at an absolute position.
|
||||||
|
|
||||||
|
@param str the string to draw.
|
||||||
|
@param buffer the frame buffer to draw into.
|
||||||
|
@param size the size of the frame buffer.
|
||||||
|
@param x the horizontal position of the topleft corner of the string.
|
||||||
|
@param y the vertical position of the topleft corner of the string. This position may be changed if it is too low to be correctly drawn.
|
||||||
|
|
||||||
|
@return \c true if everything went fine, \c false otherwise
|
||||||
|
*/
|
||||||
|
bool drawStringAbsolute(const char * str, char * buffer, const Point & size, int x, int y) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
329
scumm/smush/imuse_channel.cpp
Normal file
329
scumm/smush/imuse_channel.cpp
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "channel.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "chunck_type.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h> // for memcpy.h
|
||||||
|
#ifndef min
|
||||||
|
#define min(x, y) ((x) > (y) ? (y) : (x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImuseChannel::ImuseChannel(int track, int freq) :
|
||||||
|
_track(track),
|
||||||
|
_tbuffer(0),
|
||||||
|
_tbufferSize(0),
|
||||||
|
_sbuffer(0),
|
||||||
|
_sbufferSize(0),
|
||||||
|
_frequency(freq),
|
||||||
|
_dataSize(-1),
|
||||||
|
_inData(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ImuseChannel::~ImuseChannel() {
|
||||||
|
if(_tbuffer) {
|
||||||
|
delete []_tbuffer;
|
||||||
|
}
|
||||||
|
if(_sbuffer) {
|
||||||
|
warning("_sbuffer should be 0 !!!");
|
||||||
|
delete []_sbuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::isTerminated() const {
|
||||||
|
return (_dataSize <= 0 && _sbuffer == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::setParameters(int nbframes, int size, int unk1, int unk2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::checkParameters(int index, int nbframes, int size, int unk1, int unk2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::appendData(Chunck & b, int size) {
|
||||||
|
if(_dataSize == -1) { // First call
|
||||||
|
assert(size > 8);
|
||||||
|
Chunck::type imus_type = b.getDword(); imus_type = TO_BE_32(imus_type);
|
||||||
|
unsigned int imus_size = b.getDword(); imus_size = TO_BE_32(imus_size);
|
||||||
|
if(imus_type != TYPE_iMUS) error("Invalid CHUNCK for imuse_channel");
|
||||||
|
size -= 8;
|
||||||
|
_tbufferSize = size;
|
||||||
|
assert(_tbufferSize);
|
||||||
|
_tbuffer = new unsigned char[_tbufferSize];
|
||||||
|
if(!_tbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
b.read(_tbuffer, size);
|
||||||
|
_dataSize = -2; // even if _in_data does not get set, this won't be called again
|
||||||
|
} else {
|
||||||
|
if(_tbuffer) { // remaining from last call
|
||||||
|
unsigned char * old = _tbuffer;
|
||||||
|
int new_size = size + _tbufferSize;
|
||||||
|
_tbuffer = new unsigned char[new_size];
|
||||||
|
if(!_tbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, old, _tbufferSize);
|
||||||
|
delete []old;
|
||||||
|
b.read(_tbuffer + _tbufferSize, size);
|
||||||
|
_tbufferSize += size;
|
||||||
|
} else {
|
||||||
|
_tbufferSize = size;
|
||||||
|
_tbuffer = new unsigned char[_tbufferSize];
|
||||||
|
if(!_tbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
b.read(_tbuffer, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return processBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::handleFormat(Chunck & src) {
|
||||||
|
if(src.getSize() != 20) error("invalid size for FRMT chunck");
|
||||||
|
unsigned imuse_start = src.getDword();
|
||||||
|
imuse_start = TO_BE_32(imuse_start);
|
||||||
|
src.seek(4);
|
||||||
|
_bitsize = src.getDword();
|
||||||
|
_bitsize = TO_BE_32(_bitsize);
|
||||||
|
_rate = src.getDword();
|
||||||
|
_rate = TO_BE_32(_rate);
|
||||||
|
_channels = src.getDword();
|
||||||
|
_channels = TO_BE_32(_channels);
|
||||||
|
assert(_channels == 1 || _channels == 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::handleText(Chunck & src) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::handleRegion(Chunck & src) {
|
||||||
|
if(src.getSize() != 8) error("invalid size for REGN chunck");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::handleStop(Chunck & src) {
|
||||||
|
if(src.getSize() != 4) error("invalid size for STOP chunck");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::handleMap(Chunck & map) {
|
||||||
|
while(!map.eof()) {
|
||||||
|
Chunck * sub = map.subBlock();
|
||||||
|
switch(sub->getType()) {
|
||||||
|
case TYPE_FRMT:
|
||||||
|
handleFormat(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_TEXT:
|
||||||
|
handleText(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_REGN:
|
||||||
|
handleRegion(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_STOP:
|
||||||
|
handleStop(*sub);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown iMUS subchunck found : %s, %d", Chunck::ChunckString(sub->getType()), sub->getSize());
|
||||||
|
}
|
||||||
|
delete sub;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImuseChannel::decode() {
|
||||||
|
int remaining_size = _sbufferSize % 3;
|
||||||
|
if(remaining_size) {
|
||||||
|
_srbufferSize -= remaining_size;
|
||||||
|
assert(_inData);
|
||||||
|
if(_tbuffer == 0) {
|
||||||
|
_tbuffer = new unsigned char[remaining_size];
|
||||||
|
memcpy(_tbuffer, _sbuffer + _sbufferSize - remaining_size, remaining_size);
|
||||||
|
_tbufferSize = remaining_size;
|
||||||
|
_sbufferSize -= remaining_size;
|
||||||
|
} else {
|
||||||
|
warning("impossible ! : %p, %d, %d, %p(%d), %p(%d, %d)",
|
||||||
|
this, _dataSize, _inData, _tbuffer, _tbufferSize, _sbuffer, _sbufferSize, _srbufferSize);
|
||||||
|
unsigned char * old = _tbuffer;
|
||||||
|
int new_size = remaining_size + _tbufferSize;
|
||||||
|
_tbuffer = new unsigned char[new_size];
|
||||||
|
if(!_tbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, old, _tbufferSize);
|
||||||
|
delete []old;
|
||||||
|
memcpy(_tbuffer + _tbufferSize, _sbuffer + _sbufferSize - remaining_size, remaining_size);
|
||||||
|
_tbufferSize += remaining_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int loop_size = _sbufferSize / 3;
|
||||||
|
int new_size = loop_size * 2;
|
||||||
|
short * keep, * decoded;
|
||||||
|
keep = decoded = new short[new_size];
|
||||||
|
assert(keep);
|
||||||
|
unsigned char * source = _sbuffer;
|
||||||
|
while(loop_size--) {
|
||||||
|
int v1 = *source++;
|
||||||
|
int v2 = *source++;
|
||||||
|
int v3 = *source++;
|
||||||
|
int value = (((v2 & 0x0f) << 12) | (v1 << 4)) - 0x8000;
|
||||||
|
*decoded++ = (short)value;
|
||||||
|
value = (((v2 & 0xf0) << 8) | (v3 << 4)) - 0x8000;
|
||||||
|
*decoded++ = (short)value;
|
||||||
|
}
|
||||||
|
delete []_sbuffer;
|
||||||
|
_sbuffer = (unsigned char*)keep;
|
||||||
|
_sbufferSize = new_size * sizeof(short);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::handleSubTags(int & offset) {
|
||||||
|
int available_size = _tbufferSize - offset;
|
||||||
|
if(available_size >= 8) {
|
||||||
|
Chunck::type type = READ_BE_UINT32(_tbuffer + offset);
|
||||||
|
unsigned int size = READ_BE_UINT32(_tbuffer + offset + 4);
|
||||||
|
switch(type) {
|
||||||
|
case TYPE_MAP_:
|
||||||
|
_inData = false;
|
||||||
|
if(available_size >= (size + 8)) {
|
||||||
|
ContChunck c((char*)_tbuffer + offset);
|
||||||
|
handleMap(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TYPE_DATA: // Sound data !!!
|
||||||
|
_inData = true;
|
||||||
|
_dataSize = size;
|
||||||
|
offset += 8;
|
||||||
|
{
|
||||||
|
int reqsize = 1;
|
||||||
|
if(_channels == 2) reqsize *= 2;
|
||||||
|
if(_bitsize == 16) reqsize *= 2;
|
||||||
|
else if(_bitsize == 12) {
|
||||||
|
if(reqsize > 1)
|
||||||
|
reqsize = reqsize * 3 / 2;
|
||||||
|
else reqsize = 3;
|
||||||
|
}
|
||||||
|
if((size % reqsize) != 0) {
|
||||||
|
warning("Invalid iMUS sound data size : (%d %% %d) != 0, correcting...", size, reqsize);
|
||||||
|
size += 3 - (size % reqsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
error("unknown chunck in iMUS track : %s ", Chunck::ChunckString(type));
|
||||||
|
}
|
||||||
|
offset += size + 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImuseChannel::processBuffer() {
|
||||||
|
// see comments in saud_channel::processBuffer for an explanation
|
||||||
|
assert(_tbuffer != 0);
|
||||||
|
assert(_tbufferSize != 0);
|
||||||
|
assert(_sbuffer == 0);
|
||||||
|
assert(_sbufferSize == 0);
|
||||||
|
|
||||||
|
if(_inData) {
|
||||||
|
if(_dataSize < _tbufferSize) {
|
||||||
|
int offset= _dataSize;
|
||||||
|
while(handleSubTags(offset));
|
||||||
|
_sbufferSize = _dataSize;
|
||||||
|
_sbuffer = _tbuffer;
|
||||||
|
if(offset < _tbufferSize) { // there is still some unprocessed data
|
||||||
|
int new_size = _tbufferSize - offset;
|
||||||
|
_tbuffer = new unsigned char[new_size];
|
||||||
|
if(!_tbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, _sbuffer + offset, new_size);
|
||||||
|
_tbufferSize = new_size;
|
||||||
|
} else {
|
||||||
|
_tbuffer = 0;
|
||||||
|
_tbufferSize = 0;
|
||||||
|
}
|
||||||
|
if(_sbufferSize == 0) {
|
||||||
|
// this never happened yet, but who knows
|
||||||
|
delete []_sbuffer;
|
||||||
|
_sbuffer = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// easy, swap the buffer
|
||||||
|
_sbufferSize = _tbufferSize;
|
||||||
|
_sbuffer = _tbuffer;
|
||||||
|
_tbufferSize = 0;
|
||||||
|
_tbuffer = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int offset = 0;
|
||||||
|
while(handleSubTags(offset));
|
||||||
|
if(_inData) {
|
||||||
|
//~ unsigned char * old = _tbuffer;
|
||||||
|
_sbufferSize = _tbufferSize - offset;
|
||||||
|
assert(_sbufferSize);
|
||||||
|
_sbuffer = new unsigned char[_sbufferSize];
|
||||||
|
if(!_sbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
memcpy(_sbuffer, _tbuffer + offset, _sbufferSize);
|
||||||
|
delete []_tbuffer;
|
||||||
|
_tbuffer = 0;
|
||||||
|
_tbufferSize = 0;
|
||||||
|
} else {
|
||||||
|
if(offset) { // maybe I should assert() this to avoid a lock...
|
||||||
|
unsigned char * old = _tbuffer;
|
||||||
|
int new_size = _tbufferSize - offset;
|
||||||
|
_tbuffer = new unsigned char[new_size];
|
||||||
|
if(!_tbuffer) error("imuse_channel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, old + offset, new_size);
|
||||||
|
_tbufferSize = new_size;
|
||||||
|
delete []old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_srbufferSize = _sbufferSize;
|
||||||
|
if(_sbuffer && _bitsize == 12) decode();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImuseChannel::availableSoundData(void) const {
|
||||||
|
int ret = _sbufferSize;
|
||||||
|
if(_channels == 2) ret /= 2;
|
||||||
|
if(_bitsize > 8) ret /= 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImuseChannel::getSoundData(short * snd, int size) {
|
||||||
|
if(_dataSize <= 0 || _bitsize <= 8) error("invalid call to imuse_channel::read_sound_data()");
|
||||||
|
if(_channels == 2) size *= 2;
|
||||||
|
for(int i = 0; i < size; i++)
|
||||||
|
snd[i] = READ_BE_UINT16(_sbuffer + 2 * i);
|
||||||
|
delete []_sbuffer;
|
||||||
|
assert(_sbufferSize == 2 * size);
|
||||||
|
_sbuffer = 0;
|
||||||
|
_sbufferSize = 0;
|
||||||
|
_dataSize -= _srbufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImuseChannel::getSoundData(char * snd, int size) {
|
||||||
|
if(_dataSize <= 0 || _bitsize > 8) error("invalid call to imuse_channel::read_sound_data()");
|
||||||
|
if(_channels == 2) size *= 2;
|
||||||
|
for(int i = 0; i < size; i++)
|
||||||
|
snd[i] = _sbuffer[i];
|
||||||
|
delete []_sbuffer;
|
||||||
|
_sbuffer = 0;
|
||||||
|
_sbufferSize = 0;
|
||||||
|
_dataSize -= _srbufferSize;
|
||||||
|
}
|
58
scumm/smush/mixer.h
Normal file
58
scumm/smush/mixer.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MIXER_H_
|
||||||
|
#define __MIXER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_MIXER
|
||||||
|
# define DEBUG_MIXER
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_MIXER
|
||||||
|
# error DEBUG_MIXER defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class _Channel;
|
||||||
|
|
||||||
|
class SoundRenderer;
|
||||||
|
|
||||||
|
/*! @brief The class for the player's sound mixer
|
||||||
|
|
||||||
|
This class is used for sound mixing.
|
||||||
|
It contains a list of current track and request them to mix.
|
||||||
|
It then sends the mixed sound samples to the sound renderer.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class Mixer {
|
||||||
|
public:
|
||||||
|
virtual ~Mixer() {};
|
||||||
|
virtual bool init() = 0;
|
||||||
|
virtual _Channel * findChannel(int track) = 0;
|
||||||
|
virtual bool addChannel(_Channel * c) = 0;
|
||||||
|
virtual bool handleFrame() = 0;
|
||||||
|
virtual bool stop() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
56
scumm/smush/palette.cpp
Normal file
56
scumm/smush/palette.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "palette.h"
|
||||||
|
#include "assert.h"
|
||||||
|
|
||||||
|
Palette::Palette() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Palette::Palette(unsigned char * ptr) {
|
||||||
|
for(int i = 0; i < 256; i++) {
|
||||||
|
_colors[i] = Color(ptr[3 * i + 0], ptr[3 * i + 1], ptr[3 * i + 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Palette::Palette(const Palette & p) {
|
||||||
|
for(int i = 0; i < 256; i++) {
|
||||||
|
_colors[i] = p._colors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color & Palette::operator[](int a) const {
|
||||||
|
assert(a >= 0 && a < 256);
|
||||||
|
return _colors[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
Color & Palette::operator[](int a) {
|
||||||
|
assert(a >= 0 && a < 256);
|
||||||
|
return _colors[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
Palette & Palette::operator=(const Palette & p) {
|
||||||
|
for(int i = 0; i < 256; i++) {
|
||||||
|
_colors[i] = p._colors[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
45
scumm/smush/palette.h
Normal file
45
scumm/smush/palette.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PALETTE_H_
|
||||||
|
#define __PALETTE_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
|
||||||
|
/*! @brief simple class for handling a palette.
|
||||||
|
|
||||||
|
This small class is an helper for palettes.
|
||||||
|
*/
|
||||||
|
class Palette {
|
||||||
|
private:
|
||||||
|
Color _colors[256];
|
||||||
|
public:
|
||||||
|
Palette();
|
||||||
|
Palette(unsigned char *);
|
||||||
|
Palette(const Palette &);
|
||||||
|
const Color & operator[](int) const;
|
||||||
|
Color & operator[](int);
|
||||||
|
Palette & operator=(const Palette &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
760
scumm/smush/player.cpp
Normal file
760
scumm/smush/player.cpp
Normal file
|
@ -0,0 +1,760 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "channel.h"
|
||||||
|
#include "chunck_type.h"
|
||||||
|
#include "rect.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h> // for atoi
|
||||||
|
#include <stdio.h> // for FILE, fopen, fclose, fread, fseek, ftell
|
||||||
|
#include <string.h> // for strchr, strrchr
|
||||||
|
#include <ctype.h> // for isdigit
|
||||||
|
|
||||||
|
#ifndef max
|
||||||
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const int WAIT = 100;
|
||||||
|
|
||||||
|
/*! @brief parser and map of string resources
|
||||||
|
|
||||||
|
This class implements a parser for the string resource format of SMUSH animations.
|
||||||
|
It then allows the player to get the string corresponding to a particular identifier.
|
||||||
|
|
||||||
|
@bug some of The Dig strings are not completely parsed (in titles)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const int MAX_STRINGS = 200;
|
||||||
|
|
||||||
|
class StringResource {
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
int id;
|
||||||
|
char * string;
|
||||||
|
} _strings[MAX_STRINGS];
|
||||||
|
int _nbStrings;
|
||||||
|
int _lastId;
|
||||||
|
char * _lastString;
|
||||||
|
public:
|
||||||
|
StringResource() : _nbStrings(0), _lastId(-1) {};
|
||||||
|
~StringResource() {
|
||||||
|
for(int i = 0; i < _nbStrings; i++) {
|
||||||
|
delete []_strings[i].string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*! @brief parse the given buffer
|
||||||
|
|
||||||
|
@param buffer the buffer that contain the resource (in lucasart format)
|
||||||
|
@param length the length of the buffer
|
||||||
|
|
||||||
|
@return \c true if the parsing went fine, \c false otherwise
|
||||||
|
*/
|
||||||
|
bool init(char * buffer, int length) {
|
||||||
|
debug(9, "parsing string resources...");
|
||||||
|
char * def_start = strchr(buffer, '#');
|
||||||
|
while(def_start != NULL) {
|
||||||
|
char * def_end = strchr(def_start, '\n');
|
||||||
|
assert(def_end != NULL); // def_end is just before the start of the string [def_start,def_end] correspond to the definition text
|
||||||
|
char * id_end = def_end;
|
||||||
|
while(id_end >= def_start && !isdigit(*(id_end-1))) id_end--;
|
||||||
|
assert(id_end > def_start);
|
||||||
|
char * id_start = id_end;
|
||||||
|
while(isdigit(*(id_start - 1))) id_start--;
|
||||||
|
// [id_start-id_end] is the id number
|
||||||
|
char idstring[32];
|
||||||
|
memcpy(idstring, id_start, id_end - id_start);
|
||||||
|
idstring[id_end - id_start] = 0;
|
||||||
|
int id = atoi(idstring);
|
||||||
|
//~ assert(id != LONG_MIN && id != 0 && id != LONG_MAX);
|
||||||
|
char * data_start = def_end;
|
||||||
|
while(*data_start == '\n' || *data_start == '\r') data_start++;
|
||||||
|
char * data_end = data_start;
|
||||||
|
while(1) {
|
||||||
|
if(data_end[-2] == '\r' && data_end[1] == '\n' && data_end[-1] == '\n' && data_end[0] == '\r')
|
||||||
|
break;
|
||||||
|
data_end++;
|
||||||
|
if(data_end >= buffer + length) {
|
||||||
|
data_end = buffer + length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_end -= 2;
|
||||||
|
assert(data_end > data_start);
|
||||||
|
char * value = new char[data_end - data_start + 1];
|
||||||
|
assert(value);
|
||||||
|
memcpy(value, data_start, data_end - data_start);
|
||||||
|
value[data_end - data_start] = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(9, "Inserting (%s)%d == \"%s\"", idstring, id, value);
|
||||||
|
#endif
|
||||||
|
_strings[_nbStrings].id = id;
|
||||||
|
_strings[_nbStrings].string = value;
|
||||||
|
_nbStrings ++;
|
||||||
|
def_start = strchr(data_end + 2, '#');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*! @brief extract a string
|
||||||
|
|
||||||
|
@param id the resource identifier
|
||||||
|
|
||||||
|
@return the corresponding string.
|
||||||
|
*/
|
||||||
|
const char * get(int id) {
|
||||||
|
if(id == _lastId) return _lastString;
|
||||||
|
for(int i = 0; i < _nbStrings; i++)
|
||||||
|
{
|
||||||
|
if(_strings[i].id == id) {
|
||||||
|
_lastId = id;
|
||||||
|
_lastString = _strings[i].string;
|
||||||
|
return _strings[i].string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warning("invalid string id : %d", id);
|
||||||
|
_lastId = -1;
|
||||||
|
_lastString = "unknown string";
|
||||||
|
return _lastString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void SmushPlayer::show(const char * p) {
|
||||||
|
if(strcmp(p, "subtitles") == 0)
|
||||||
|
_subtitles = true;
|
||||||
|
else if(strcmp(p, "bgmusic") == 0)
|
||||||
|
_bgmusic = true;
|
||||||
|
else if(strcmp(p, "voices") == 0)
|
||||||
|
_voices = true;
|
||||||
|
else {
|
||||||
|
int id = atoi(p);
|
||||||
|
if(id < 0 || id > 36) error("invalid parameter to show");
|
||||||
|
_skips[id] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::hide(const char * p) {
|
||||||
|
if(strcmp(p, "subtitles") == 0)
|
||||||
|
_subtitles = false;
|
||||||
|
else if(strcmp(p, "bgmusic") == 0)
|
||||||
|
_bgmusic = false;
|
||||||
|
else if(strcmp(p, "voices") == 0)
|
||||||
|
_voices = false;
|
||||||
|
else {
|
||||||
|
int id = atoi(p);
|
||||||
|
if(id < 0 || id > 36) error("invalid parameter to hide");
|
||||||
|
_skips[id] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SmushPlayer::SmushPlayer(Renderer * renderer, bool wait, bool sound) :
|
||||||
|
_version(-1),
|
||||||
|
_secondaryVersion(0),
|
||||||
|
_soundFrequency(0),
|
||||||
|
_nbframes(0),
|
||||||
|
_mixer(0),
|
||||||
|
_renderer(renderer),
|
||||||
|
_strings(0),
|
||||||
|
_frameSize(-1, -1),
|
||||||
|
_frame(0),
|
||||||
|
_outputSound(sound),
|
||||||
|
_wait(wait),
|
||||||
|
_alreadyInit(false),
|
||||||
|
_codec37Called(false),
|
||||||
|
_skipNext(false),
|
||||||
|
_subtitles(true),
|
||||||
|
_bgmusic(true),
|
||||||
|
_voices(true) {
|
||||||
|
_fr[0] = _fr[1] = _fr[2] = _fr[3] = 0;
|
||||||
|
assert(_renderer != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SmushPlayer::~SmushPlayer() {
|
||||||
|
clean();
|
||||||
|
//~ if(_mixer) delete _mixer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::updatePalette(void) {
|
||||||
|
_renderer->setPalette(_pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::clean() {
|
||||||
|
if(_strings)
|
||||||
|
delete _strings;
|
||||||
|
if(_fr[0]) delete _fr[0];
|
||||||
|
if(_fr[1]) delete _fr[1];
|
||||||
|
if(_fr[2]) delete _fr[2];
|
||||||
|
if(_fr[3]) delete _fr[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::checkBlock(const Chunck & b, Chunck::type type_expected, unsigned int min_size) {
|
||||||
|
if(type_expected != b.getType()) {
|
||||||
|
error("chunck type is different from expected : %d != %d", b.getType(), type_expected);
|
||||||
|
}
|
||||||
|
if(min_size > b.getSize()) {
|
||||||
|
error( "chunck size is inferior than minimum required size : %d < %d", b.getSize(), min_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleSoundBuffer(int track_id, int index, int max_frames, int flags, int vol, int bal, Chunck & b, int size) {
|
||||||
|
debug(6, "smush_player::handleSoundBuffer(%d)", track_id);
|
||||||
|
if(!_voices && (flags & 128) == 128) return;
|
||||||
|
if(!_bgmusic && (flags & 64) == 64) return;
|
||||||
|
_Channel * c = _mixer->findChannel(track_id);
|
||||||
|
if(c == 0) {
|
||||||
|
c = new SaudChannel(track_id, _soundFrequency);
|
||||||
|
_mixer->addChannel(c);
|
||||||
|
}
|
||||||
|
if(index == 0)
|
||||||
|
c->setParameters(max_frames, flags, vol, bal);
|
||||||
|
else
|
||||||
|
c->checkParameters(index, max_frames, flags, vol, bal);
|
||||||
|
c->appendData(b, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleSoundFrame(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_PSAD);
|
||||||
|
debug(6, "SmushPlayer::handleSoundFrame()");
|
||||||
|
if(!_outputSound) return;
|
||||||
|
int track_id = b.getWord();
|
||||||
|
int index = b.getWord();
|
||||||
|
int max_frames = b.getWord();
|
||||||
|
int flags = b.getWord();
|
||||||
|
int vol = b.getByte();
|
||||||
|
int bal = b.getChar();
|
||||||
|
#ifdef DEBUG
|
||||||
|
if(index == 0) {
|
||||||
|
debug(5, "track_id == %d, max_frames == %d, %d, %d, %d", track_id, max_frames, flags, vol, bal);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
int size = b.getSize() - 10;
|
||||||
|
handleSoundBuffer(track_id, index, max_frames, flags, vol, bal, b, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleSkip(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_SKIP, 4);
|
||||||
|
int code = b.getDword();
|
||||||
|
debug(6, "SmushPlayer::handleSkip(%d)", code);
|
||||||
|
if(code >= 0 && code < 37)
|
||||||
|
_skipNext =_skips[code];
|
||||||
|
else
|
||||||
|
_skipNext =true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleStore(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_STOR, 4);
|
||||||
|
debug(6, "SmushPlayer::handleStore()");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleFetch(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_FTCH, 6);
|
||||||
|
debug(6, "SmushPlayer::handleFetch()");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleImuseBuffer(int track_id, int index, int nbframes, int size, int unk1, int unk2, Chunck & b, int bsize) {
|
||||||
|
_Channel * c = _mixer->findChannel(track_id);
|
||||||
|
if(c == 0) {
|
||||||
|
c = new ImuseChannel(track_id, _soundFrequency);
|
||||||
|
_mixer->addChannel(c);
|
||||||
|
}
|
||||||
|
if(index == 0)
|
||||||
|
c->setParameters(nbframes, size, unk1, unk2);
|
||||||
|
else
|
||||||
|
c->checkParameters(index, nbframes, size, unk1, unk2);
|
||||||
|
c->appendData(b, bsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleImuseAction8(Chunck & b, int flags, int unknown, int track_id) {
|
||||||
|
assert(flags == 46 && unknown == 0);
|
||||||
|
int unknown2 = b.getWord();
|
||||||
|
track_id |= unknown2 << 16;
|
||||||
|
int index = b.getWord();
|
||||||
|
int nbframes = b.getWord();
|
||||||
|
int size = b.getDword();
|
||||||
|
int bsize = b.getSize() - 18;
|
||||||
|
handleImuseBuffer(track_id, index, nbframes, size, unknown, unknown2, b, bsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleImuseAction(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_IACT, 8);
|
||||||
|
debug(6, "SmushPlayer::handleImuseAction()");
|
||||||
|
if(!_outputSound) return;
|
||||||
|
int code = b.getWord();
|
||||||
|
int flags = b.getWord();
|
||||||
|
int unknown = b.getShort();
|
||||||
|
int track_id = b.getWord();
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "handleImuseAction(%d, %d, %d, %d)", code, flags, unknown, track_id);
|
||||||
|
#endif
|
||||||
|
switch(code) {
|
||||||
|
case 8:
|
||||||
|
handleImuseAction8(b, flags, unknown, track_id);
|
||||||
|
break;
|
||||||
|
#ifdef DEBUG
|
||||||
|
default: {
|
||||||
|
debug(9, "%5.5d %d %8.8d %4.4d", track_id, flags, unknown);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleTextResource(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_TRES, 18);
|
||||||
|
int pos_x = b.getShort();
|
||||||
|
int pos_y = b.getShort();
|
||||||
|
int flags = b.getShort();
|
||||||
|
int left = b.getShort();
|
||||||
|
int top = b.getShort();
|
||||||
|
int width = b.getShort();
|
||||||
|
int height = b.getShort();
|
||||||
|
int unk2 = b.getWord();
|
||||||
|
int string_id = b.getWord();
|
||||||
|
debug(6, "SmushPlayer::handleTextResource(%d)", string_id);
|
||||||
|
if(!_strings) return;
|
||||||
|
|
||||||
|
// if subtitles disabled and bit 3 is set, then do not draw
|
||||||
|
if((!_subtitles) && ((flags & 8) == 8)) return;
|
||||||
|
const char * str = _strings->get(string_id);
|
||||||
|
|
||||||
|
FontRenderer * fr = _fr[0];
|
||||||
|
int color = 15;
|
||||||
|
while(*str == '/') str++; // For Full Throttle text resources
|
||||||
|
while(str[0] == '^') {
|
||||||
|
switch(str[1]) {
|
||||||
|
case 'f':
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// This cause trouble if the next character is a digit.
|
||||||
|
int id = atoi(str+2);
|
||||||
|
#else
|
||||||
|
// assume ASCII like character set...
|
||||||
|
int id = str[3] - '0';
|
||||||
|
#endif
|
||||||
|
str += 4;
|
||||||
|
fr = _fr[id];
|
||||||
|
} break;
|
||||||
|
case 'c':
|
||||||
|
{
|
||||||
|
//~ int id = atoi(str+2);
|
||||||
|
color = str[4] - '0' + 10 *(str[3] - '0');
|
||||||
|
str += 5;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
error("invalid escape code in text string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(fr != 0);
|
||||||
|
fr->setColor(color);
|
||||||
|
if(!_curBuffer) { _curBuffer = _renderer->lockFrame(_frame); }
|
||||||
|
if(flags == 0 || flags == 4) {
|
||||||
|
fr->drawStringAbsolute(str, _curBuffer, _frameSize, pos_x, pos_y);
|
||||||
|
} else {
|
||||||
|
fr->drawStringCentered(str, _curBuffer, _frameSize, max(pos_y, top), left, width, pos_x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::readPalette(Palette & out, Chunck & in) {
|
||||||
|
unsigned char buffer[768];
|
||||||
|
in.read(buffer, 768);
|
||||||
|
out = Palette(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleDeltaPalette(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_XPAL);
|
||||||
|
debug(6, "SmushPlayer::handleDeltaPalette()");
|
||||||
|
if(b.getSize() == 768 * 3 + 4) {
|
||||||
|
int unk1, num;
|
||||||
|
unk1 = b.getWord();
|
||||||
|
num = b.getWord();
|
||||||
|
for(int i = 0; i < 768; i++) {
|
||||||
|
_deltaPal[i] = b.getWord();
|
||||||
|
}
|
||||||
|
readPalette(_pal, b);
|
||||||
|
updatePalette();
|
||||||
|
} else if(b.getSize() == 6) {
|
||||||
|
int unk1, num, unk2;
|
||||||
|
unk1 = b.getWord();
|
||||||
|
num = b.getWord();
|
||||||
|
unk2 = b.getWord();
|
||||||
|
for(int i = 0; i < 256; i++) {
|
||||||
|
_pal[i].delta(_deltaPal + 3 * i);
|
||||||
|
}
|
||||||
|
updatePalette();
|
||||||
|
} else {
|
||||||
|
error("wrong size for DeltaPalette");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleNewPalette(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_NPAL, 768);
|
||||||
|
debug(6, "SmushPlayer::handleNewPalette()");
|
||||||
|
readPalette(_pal, b);
|
||||||
|
updatePalette();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::decodeCodec(Chunck & b, const Rect & r, Decoder & codec) {
|
||||||
|
assert(_curBuffer);
|
||||||
|
Blitter blit(_curBuffer, _frameSize, r);
|
||||||
|
codec.decode(blit, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::initSize(const Rect & r, bool always, bool transparent) {
|
||||||
|
if(_codec37Called) _alreadyInit = true;
|
||||||
|
|
||||||
|
if(!_alreadyInit || _frameSize.getX() < r.right() || _frameSize.getY() < r.bottom() || always) {
|
||||||
|
if(_curBuffer) {
|
||||||
|
_renderer->unlockFrame();
|
||||||
|
_curBuffer = 0;
|
||||||
|
}
|
||||||
|
_frameSize = r.bottomRight();
|
||||||
|
_renderer->initFrame(_frameSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_curBuffer) {
|
||||||
|
_renderer->unlockFrame();
|
||||||
|
_curBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_curBuffer = _renderer->lockFrame(_frame);
|
||||||
|
if(!_alreadyInit && transparent) {
|
||||||
|
memset(_curBuffer, 0, _frameSize.getX()*_frameSize.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
_codec1.initSize(_frameSize, r);
|
||||||
|
_codec37.initSize(_frameSize, r);
|
||||||
|
_codec44.initSize(_frameSize, r);
|
||||||
|
_codecd.initSize(_frameSize, r);
|
||||||
|
_alreadyInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleFrameObject(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_FOBJ, 14);
|
||||||
|
if(_skipNext) {
|
||||||
|
_skipNext = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int codec = b.getWord();
|
||||||
|
debug(6, "SmushPlayer::handleFrameObject(%d)", codec);
|
||||||
|
unsigned short left = b.getWord();
|
||||||
|
unsigned short top = b.getWord();
|
||||||
|
unsigned short width = b.getWord();
|
||||||
|
unsigned short height = b.getWord();
|
||||||
|
Rect r(left, top, left + width, top + height);
|
||||||
|
unsigned short data[2];
|
||||||
|
data[1] = b.getWord();
|
||||||
|
data[0] = b.getWord();
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "Frame pos : %d, %d", left, top);
|
||||||
|
debug(5, "Frame size : %dx%d", width, height);
|
||||||
|
debug(5, "Codec : %d", codec);
|
||||||
|
#endif
|
||||||
|
switch (codec) {
|
||||||
|
case 3:
|
||||||
|
case 1:
|
||||||
|
initSize(r, false, true);
|
||||||
|
decodeCodec(b, r, _codec1);
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
assert(left == 0 && top == 0);
|
||||||
|
initSize(r, true, false);
|
||||||
|
decodeCodec(b, r, _codec37);
|
||||||
|
_codec37Called = true;
|
||||||
|
break;
|
||||||
|
case 47:
|
||||||
|
initSize(r, false, true);
|
||||||
|
decodeCodec(b, r, _codecd);
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
case 44:
|
||||||
|
initSize(r, true, true);
|
||||||
|
decodeCodec(b, r, _codec44);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Invalid codec for frame object : %d", (int)codec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleFrame(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_FRME);
|
||||||
|
debug(6, "SmushPlayer::handleFrame(%d)", _frame);
|
||||||
|
_alreadyInit = false;
|
||||||
|
_skipNext = false;
|
||||||
|
|
||||||
|
while(!b.eof()) {
|
||||||
|
Chunck * sub = b.subBlock();
|
||||||
|
if(sub->getSize() & 1) b.seek(1);
|
||||||
|
switch(sub->getType()) {
|
||||||
|
case TYPE_NPAL:
|
||||||
|
handleNewPalette(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_FOBJ:
|
||||||
|
handleFrameObject(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_PSAD:
|
||||||
|
handleSoundFrame(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_TRES:
|
||||||
|
handleTextResource(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_XPAL:
|
||||||
|
handleDeltaPalette(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_IACT:
|
||||||
|
handleImuseAction(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_STOR:
|
||||||
|
handleStore(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_FTCH:
|
||||||
|
handleFetch(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_SKIP:
|
||||||
|
handleSkip(*sub);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown frame subchunck found : %s, %d", Chunck::ChunckString(sub->getType()), sub->getSize());
|
||||||
|
}
|
||||||
|
delete sub;
|
||||||
|
}
|
||||||
|
if(_curBuffer) {
|
||||||
|
_renderer->unlockFrame();
|
||||||
|
_curBuffer = 0;
|
||||||
|
}
|
||||||
|
if(_outputSound)
|
||||||
|
_mixer->handleFrame();
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "===================END OF FRAME========================");
|
||||||
|
#endif
|
||||||
|
_renderer->flipFrame();
|
||||||
|
if(_wait)
|
||||||
|
_renderer->wait(WAIT);
|
||||||
|
_frame++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmushPlayer::handleAnimHeader(Chunck & b) {
|
||||||
|
checkBlock(b, TYPE_AHDR, 774);
|
||||||
|
debug(6, "SmushPlayer::handleAnimHeader()");
|
||||||
|
_version = b.getWord();
|
||||||
|
_nbframes = b.getWord();
|
||||||
|
int unknown = b.getWord();
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "SMUSH HEADER : version == %d, nbframes == %d, unknown == %d", _version, _nbframes, unknown);
|
||||||
|
#else
|
||||||
|
unknown = unknown;
|
||||||
|
#endif
|
||||||
|
_renderer->startDecode(_fname, _version, _nbframes);
|
||||||
|
readPalette(_pal, b);
|
||||||
|
updatePalette();
|
||||||
|
if(_version == 1) {
|
||||||
|
_soundFrequency = 22050;
|
||||||
|
}
|
||||||
|
if(_version == 2) {
|
||||||
|
_secondaryVersion = b.getDword();
|
||||||
|
int unknown2 = b.getDword();
|
||||||
|
_soundFrequency = b.getDword();
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "SMUSH HEADER : secondary version == %d, unknown2 == %d, sound frequency == %d", _secondaryVersion, unknown2, _soundFrequency);
|
||||||
|
int i = 0, c;
|
||||||
|
while(!b.eof()) {
|
||||||
|
c = b.getByte();
|
||||||
|
if(c) debug(9, "SMUSH HEADER : remaining bytes : %d == %d", i, c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
unknown2 = unknown2;
|
||||||
|
#endif
|
||||||
|
if(_secondaryVersion != 10 && _secondaryVersion != 0 && _secondaryVersion != 12 && _secondaryVersion != 15 && _secondaryVersion != 14)
|
||||||
|
error("Wrong secondary version number for SMUSH animation");
|
||||||
|
if(_soundFrequency != 0 && _soundFrequency != 11025 && _soundFrequency != 22050)
|
||||||
|
error("Wrong _sound_frequency number for SMUSH animation");
|
||||||
|
}else if(_version > 2) {
|
||||||
|
error("Wrong primary version number for SMUSH animation");
|
||||||
|
}
|
||||||
|
if(_outputSound && _soundFrequency) {
|
||||||
|
if(_soundFrequency != 22050) _soundFrequency = 22050;
|
||||||
|
_mixer = _renderer->getMixer();
|
||||||
|
if(_mixer) {
|
||||||
|
_mixer->init();
|
||||||
|
} else {
|
||||||
|
_outputSound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringResource * getStrings(const char * file, bool is_encoded) {
|
||||||
|
debug(7, "trying to read text ressources from %s", file);
|
||||||
|
FILE * is;
|
||||||
|
is = fopen(file, "rb");
|
||||||
|
if(is == NULL) return 0;
|
||||||
|
fseek(is, 0, SEEK_END);
|
||||||
|
int length = ftell(is);
|
||||||
|
fseek(is, 0, SEEK_SET);
|
||||||
|
char * filebuffer = new char [length + 1];
|
||||||
|
assert(filebuffer);
|
||||||
|
fread (filebuffer, length, 1, is);
|
||||||
|
filebuffer[length] = 0;
|
||||||
|
fclose(is);
|
||||||
|
if(is_encoded) {
|
||||||
|
static const int ETRS_HEADER_LENGTH = 16;
|
||||||
|
assert(length > ETRS_HEADER_LENGTH);
|
||||||
|
Chunck::type type = READ_BE_UINT32(filebuffer);
|
||||||
|
if(type != TYPE_ETRS) error("invalid type for file"); // mem leak !!!
|
||||||
|
char * old = filebuffer;
|
||||||
|
filebuffer = new char[length - ETRS_HEADER_LENGTH];
|
||||||
|
for(int i = ETRS_HEADER_LENGTH; i < length; i++)
|
||||||
|
filebuffer[i - ETRS_HEADER_LENGTH] = old[i] ^ 0xCC;
|
||||||
|
delete []old;
|
||||||
|
length -= ETRS_HEADER_LENGTH;
|
||||||
|
}
|
||||||
|
StringResource * sr = new StringResource;
|
||||||
|
assert(sr);
|
||||||
|
sr->init(filebuffer, length);
|
||||||
|
delete []filebuffer;
|
||||||
|
return sr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SmushPlayer::readString(const char * file, bool & ft) {
|
||||||
|
const char * i = strrchr(file, '.');
|
||||||
|
if(i == NULL) error("invalid filename : %s", file);
|
||||||
|
char fname[260];
|
||||||
|
memcpy(fname, file, i - file);
|
||||||
|
strcpy(fname + (i - file), ".trs");
|
||||||
|
if((_strings = getStrings(fname, false)) != 0) {
|
||||||
|
ft = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
i = strrchr(file, '\\');
|
||||||
|
if(i == NULL) i = strrchr(file, '/');
|
||||||
|
else {
|
||||||
|
char * j = strrchr(file, '/');
|
||||||
|
if(j > i) i = j;
|
||||||
|
}
|
||||||
|
if(i == NULL) error("invalid filename : %s", file);
|
||||||
|
|
||||||
|
memcpy(fname, file, i - file + 1);
|
||||||
|
strcpy(fname + (i - file + 1), "digtxt.trs");
|
||||||
|
if((_strings = getStrings(fname, true)) != 0) {
|
||||||
|
ft = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FontRenderer * loadFont(const char * file, bool original = false) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "loading font from \"%s\"", file);
|
||||||
|
#endif
|
||||||
|
FontRenderer * fr = new FontRenderer(original);
|
||||||
|
SmushPlayer p(fr, false, false);
|
||||||
|
p.play(file);
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SmushPlayer::play(const char * file) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "start of animation : %s", file);
|
||||||
|
#endif
|
||||||
|
char * i = strrchr(file, '\\');
|
||||||
|
if(i == NULL)
|
||||||
|
{
|
||||||
|
i = strrchr(file, '/');
|
||||||
|
} else {
|
||||||
|
char * j = strrchr(i, '/');
|
||||||
|
if(j != NULL)
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
char directory[260];
|
||||||
|
if(i != NULL) {
|
||||||
|
strcpy(directory, file);
|
||||||
|
directory[i-file] = 0;
|
||||||
|
//! @todo remove this...
|
||||||
|
_fname = strdup(i);
|
||||||
|
} else {
|
||||||
|
directory[0] = 0;
|
||||||
|
_fname = strdup(file);
|
||||||
|
}
|
||||||
|
clean();
|
||||||
|
|
||||||
|
if(_wait) {
|
||||||
|
bool isFullthrottle;
|
||||||
|
if(!readString(file, isFullthrottle))
|
||||||
|
warning("unable to read text information for \"%s\"", file);
|
||||||
|
if(_strings) {
|
||||||
|
if(isFullthrottle) {
|
||||||
|
if(strcmp(directory, "") == 0) {
|
||||||
|
strcpy(directory, "../data/");
|
||||||
|
} else {
|
||||||
|
char * i = strrchr(directory, '\\');
|
||||||
|
char * j = strrchr(directory, '/');
|
||||||
|
if(j > i) i = j;
|
||||||
|
if(i == NULL) {
|
||||||
|
strcpy(directory, "data/");
|
||||||
|
} else {
|
||||||
|
*i = 0;
|
||||||
|
strcat(directory, "/data/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char file[260];
|
||||||
|
strcpy(file, directory); strcat(file, "scummfnt.nut");
|
||||||
|
_fr[0] = loadFont(file, true);
|
||||||
|
strcpy(file, directory); strcat(file, "titlfnt.nut");
|
||||||
|
_fr[2] = loadFont(file, true);
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < 4; i++) {
|
||||||
|
char file[260];
|
||||||
|
sprintf(file, "%s/font%d.nut",directory, i);
|
||||||
|
_fr[i] = loadFont(file, i != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FileChunck base = FileChunck(file);
|
||||||
|
|
||||||
|
checkBlock(base, TYPE_ANIM);
|
||||||
|
|
||||||
|
while(!base.eof()) {
|
||||||
|
Chunck * sub = base.subBlock();
|
||||||
|
switch(sub->getType()) {
|
||||||
|
case TYPE_AHDR:
|
||||||
|
handleAnimHeader(*sub);
|
||||||
|
break;
|
||||||
|
case TYPE_FRME:
|
||||||
|
handleFrame(*sub);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown chunck found : %d, %d", sub->getType(), sub->getSize());
|
||||||
|
}
|
||||||
|
delete sub;
|
||||||
|
if(_renderer->prematureClose())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
debug(5, "end of animation");
|
||||||
|
#endif
|
||||||
|
if(_outputSound) {
|
||||||
|
_mixer->stop();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
104
scumm/smush/player.h
Normal file
104
scumm/smush/player.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLAYER_H_
|
||||||
|
#define __PLAYER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "rect.h"
|
||||||
|
#include "mixer.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "palette.h"
|
||||||
|
#include "codec1.h"
|
||||||
|
#include "codec37.h"
|
||||||
|
#include "codec44.h"
|
||||||
|
#include "codec47.h"
|
||||||
|
#include "frenderer.h"
|
||||||
|
|
||||||
|
class Renderer;
|
||||||
|
|
||||||
|
class StringResource;
|
||||||
|
|
||||||
|
/*! @brief the SMUSH player class
|
||||||
|
|
||||||
|
This class is the player itself.
|
||||||
|
*/
|
||||||
|
class SmushPlayer {
|
||||||
|
private:
|
||||||
|
char * _fname; //!< the name of the animation file being played
|
||||||
|
int _version; //!< the version of the animation file being played
|
||||||
|
int _secondaryVersion; //!< the secondary version number of the animation file being played
|
||||||
|
int _soundFrequency; //!< the sound frequency of the animation file being played
|
||||||
|
int _nbframes; //!< the number of frames in the animation file
|
||||||
|
Mixer * _mixer; //!< the sound mixer
|
||||||
|
Palette _pal; //!< the current palette
|
||||||
|
short _deltaPal[768]; //!< the delta palette information set by an xpal
|
||||||
|
Renderer * _renderer; //!< pointer to the ::renderer
|
||||||
|
StringResource * _strings; //!< pointer to the string resources associated with the animation
|
||||||
|
FontRenderer * _fr[4]; //!< pointers to the fonts for the animation
|
||||||
|
Codec1Decoder _codec1; //!< the ::decoder for codec 1 and 3
|
||||||
|
Codec37Decoder _codec37; //!< the ::decoder for codec 37
|
||||||
|
Codec44Decoder _codec44; //!< the ::decoder for codec 21 and 44
|
||||||
|
DumpDecoder _codecd; //!< the ::decoder for codec 21 and 44
|
||||||
|
Point _frameSize; //!< the current frame size of the animation
|
||||||
|
int _frame; //!< the current frame number of the animation
|
||||||
|
bool _outputSound; //!< should we handle sound ?
|
||||||
|
bool _wait; //!< should we synchronise the player ?
|
||||||
|
bool _alreadyInit; //!< has the player already been initialized for the current frame
|
||||||
|
bool _codec37Called; //!< has the codec 37 already been called once for this animation
|
||||||
|
bool _skipNext; //!< should the player skip the next frame object ?
|
||||||
|
bool _subtitles; //!< should the player handle subtitles ?
|
||||||
|
bool _bgmusic; //!< should the player output the background music ?
|
||||||
|
bool _voices; //!< should the player output the voice ?
|
||||||
|
bool _skips[37]; //!< mapping of frame object identifier to show or hide
|
||||||
|
char * _curBuffer; //!< pointer to the current frame
|
||||||
|
public:
|
||||||
|
SmushPlayer(Renderer *, bool wait = true, bool output_sound = true);
|
||||||
|
virtual ~SmushPlayer();
|
||||||
|
bool play(const char *);
|
||||||
|
void updatePalette(void);
|
||||||
|
void show(const char *);
|
||||||
|
void hide(const char *);
|
||||||
|
protected:
|
||||||
|
bool readString(const char * file, bool &);
|
||||||
|
void clean();
|
||||||
|
void checkBlock(const Chunck &, Chunck::type, unsigned int = 0);
|
||||||
|
void handleAnimHeader(Chunck &);
|
||||||
|
void handleFrame(Chunck &);
|
||||||
|
void handleNewPalette(Chunck &);
|
||||||
|
void handleFrameObject(Chunck &);
|
||||||
|
void handleSoundBuffer(int, int, int, int, int, int, Chunck &, int);
|
||||||
|
void handleImuseBuffer(int, int, int, int, int, int, Chunck &, int);
|
||||||
|
void handleSoundFrame(Chunck &);
|
||||||
|
void handleSkip(Chunck &);
|
||||||
|
void handleStore(Chunck &);
|
||||||
|
void handleFetch(Chunck &);
|
||||||
|
void handleImuseAction8(Chunck &, int flags, int unknown, int track_id);
|
||||||
|
void handleImuseAction(Chunck &);
|
||||||
|
void handleTextResource(Chunck &);
|
||||||
|
void handleDeltaPalette(Chunck &);
|
||||||
|
void decodeCodec(Chunck &, const Rect &, Decoder &);
|
||||||
|
void readPalette(Palette &, Chunck &);
|
||||||
|
void initSize(const Rect &, bool, bool);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
62
scumm/smush/rect.cpp
Normal file
62
scumm/smush/rect.cpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
Rect::Rect() : _topLeft(0, 0), _bottomRight(0,0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect::Rect(int x, int y) : _topLeft(0, 0), _bottomRight(x, y) {
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect::Rect(int x1, int y1, int x2, int y2) : _topLeft(x1, y1), _bottomRight(x2, y2) {
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect::Rect(const Rect & r) : _topLeft(r._topLeft), _bottomRight(r._bottomRight) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect & Rect::operator=(const Rect & r) {
|
||||||
|
_topLeft = r._topLeft;
|
||||||
|
_bottomRight = r._bottomRight;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rect::operator==(const Rect & r) const {
|
||||||
|
return _topLeft == r._topLeft && _bottomRight == r._bottomRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rect::check() {
|
||||||
|
if ((_topLeft.getX() < 0) || (_bottomRight.getX() < _topLeft.getX()) || (_topLeft.getY() < 0) || (_bottomRight.getY() < _topLeft.getY())) {
|
||||||
|
error("Invalid rect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rect::isInside(int x, int y) const {
|
||||||
|
return _topLeft.getX() >= x && _bottomRight.getX() < x && _topLeft.getY() >= y && _bottomRight.getY() < y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Rect::isInside(const Point & p) const {
|
||||||
|
return (left() <= p.getX()) && (right() > p.getX()) && (top() <= p.getY()) && (bottom() > p.getY());
|
||||||
|
}
|
||||||
|
|
101
scumm/smush/rect.h
Normal file
101
scumm/smush/rect.h
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RECT_H_
|
||||||
|
#define __RECT_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/*! @brief simple class for handling both 2D position and size
|
||||||
|
|
||||||
|
This small class is an helper for position and size values.
|
||||||
|
*/
|
||||||
|
class Point {
|
||||||
|
private:
|
||||||
|
int _x; //!< The horizontal part of the point
|
||||||
|
int _y; //!< The vertical part of the point
|
||||||
|
public:
|
||||||
|
Point() : _x(0), _y(0) {};
|
||||||
|
Point(const Point & p) : _x(p.getX()), _y(p.getY()) {};
|
||||||
|
explicit Point(int x, int y) : _x(x), _y(y) {};
|
||||||
|
Point & operator=(const Point & p) { _x = p.getX(); _y = p.getY(); return *this; };
|
||||||
|
bool operator==(const Point & p) const { return _x == p.getX() && _y == p.getY(); };
|
||||||
|
const int & getX() const { return _x; };
|
||||||
|
const int & getY() const { return _y; };
|
||||||
|
int & getX() { return _x; };
|
||||||
|
int & getY() { return _y; };
|
||||||
|
Point operator+(const Point & p) const { return Point(_x + p.getX(), _y+p.getY()); };
|
||||||
|
Point operator-(const Point & p) const { return Point(_x - p.getX(), _y-p.getY()); };
|
||||||
|
Point & operator+=(const Point & p) { _x += p.getX(); _y += p.getY(); return *this; };
|
||||||
|
Point & operator-=(const Point & p) { _x -= p.getX(); _y -= p.getY(); return *this; };
|
||||||
|
bool isOrigin() const { return *this == Point(0, 0); };
|
||||||
|
void set(int x, int y) { _x = x; _y = y; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! @brief simple class for handling a rectangular zone.
|
||||||
|
|
||||||
|
This small class is an helper for rectangles.
|
||||||
|
It is mostly used by the blitter class.
|
||||||
|
*/
|
||||||
|
class Rect {
|
||||||
|
private:
|
||||||
|
Point _topLeft; //!< The point at the top left of the rectangle
|
||||||
|
Point _bottomRight; //!< The point at the bottom right of the rectangle
|
||||||
|
protected:
|
||||||
|
void check();
|
||||||
|
public:
|
||||||
|
Rect();
|
||||||
|
Rect(int x, int y);
|
||||||
|
explicit Rect(const Point & size);
|
||||||
|
Rect(int x1, int y1, int x2, int y2);
|
||||||
|
Rect(const Point & topleft, const Point & bottomright);
|
||||||
|
Rect(const Rect & r);
|
||||||
|
Rect & operator=(const Rect & r);
|
||||||
|
bool operator==(const Rect & r) const;
|
||||||
|
Point size() const { return (_bottomRight - _topLeft); };
|
||||||
|
int width() const { return size().getX(); }
|
||||||
|
int height() const { return size().getY(); }
|
||||||
|
int left() const { return _topLeft.getX(); }
|
||||||
|
int right() const { return _bottomRight.getX(); }
|
||||||
|
int top() const { return _topLeft.getY(); }
|
||||||
|
int bottom() const { return _bottomRight.getY(); }
|
||||||
|
const Point & topLeft() const { return _topLeft; }
|
||||||
|
const Point & bottomRight() const { return _bottomRight; }
|
||||||
|
|
||||||
|
/*! @brief check if given position is inside the rectangle
|
||||||
|
|
||||||
|
@param x the horizontal position to check
|
||||||
|
@param y the vertical position to check
|
||||||
|
|
||||||
|
@return true if the given position is inside the rectangle, false otherwise
|
||||||
|
*/
|
||||||
|
bool isInside(int x, int y) const;
|
||||||
|
/*! @brief check if given point is inside the rectangle
|
||||||
|
|
||||||
|
@param p the point to check
|
||||||
|
|
||||||
|
@return true if the given point is inside the rectangle, false otherwise
|
||||||
|
*/
|
||||||
|
bool isInside(const Point & p) const;
|
||||||
|
bool clip(Rect & r) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
123
scumm/smush/renderer.h
Normal file
123
scumm/smush/renderer.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RENDERER_H_
|
||||||
|
#define __RENDERER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "rect.h"
|
||||||
|
|
||||||
|
class Palette;
|
||||||
|
class Mixer;
|
||||||
|
|
||||||
|
/*! @brief interface for general output (rendering)
|
||||||
|
|
||||||
|
This is the interface for frame output.
|
||||||
|
Several implementations of these interface exist, each having a particular
|
||||||
|
application.
|
||||||
|
*/
|
||||||
|
class Renderer {
|
||||||
|
public:
|
||||||
|
virtual ~Renderer() {};
|
||||||
|
/*! @brief start of animation output
|
||||||
|
|
||||||
|
This is called by the animation player when output is going to start.
|
||||||
|
|
||||||
|
@param fname name of the animation being played.
|
||||||
|
@param version version number of the animation
|
||||||
|
@param nbframes total number of frames of the animation.
|
||||||
|
|
||||||
|
@return true if initialisation was ok, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool startDecode(const char * fname, int version, int nbframes) = 0;
|
||||||
|
/*! @brief start of animation output
|
||||||
|
|
||||||
|
This is called by the animation player when the frame size is changing.
|
||||||
|
|
||||||
|
@param size new size of the frames.
|
||||||
|
|
||||||
|
@return true if everything went fine, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool initFrame(const Point & size) = 0;
|
||||||
|
/*! @brief set a new palette
|
||||||
|
|
||||||
|
This is called by the animation player when the palette is changing.
|
||||||
|
|
||||||
|
@param pal new palette.
|
||||||
|
|
||||||
|
@return true if everything went fine, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool setPalette(const Palette & pal) = 0;
|
||||||
|
/*! @brief lock a frame buffer
|
||||||
|
|
||||||
|
This is called by the animation player when a frame is going to be decoded.
|
||||||
|
|
||||||
|
@param frame the frame number.
|
||||||
|
|
||||||
|
@return a pointer to the frame buffer to output data to.
|
||||||
|
*/
|
||||||
|
virtual char * lockFrame(int frame) = 0;
|
||||||
|
/*! @brief unlock a frame buffer
|
||||||
|
|
||||||
|
This is called by the animation player when a frame has been decoded.
|
||||||
|
|
||||||
|
@return true if everything went fine, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool unlockFrame() = 0;
|
||||||
|
/*! @brief flip a frame buffer
|
||||||
|
|
||||||
|
This is called by the animation player when the current frame should be shown.
|
||||||
|
|
||||||
|
@return true if everything went fine, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool flipFrame() = 0;
|
||||||
|
/*! @brief wait for some time
|
||||||
|
|
||||||
|
This is called by the animation player when the animation should stay idle.
|
||||||
|
|
||||||
|
@param ms number of millisecond to wait.
|
||||||
|
|
||||||
|
@return true if everything went fine, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool wait(int ms) = 0;
|
||||||
|
/*! @brief does the renderer want a premature end of the animation ?
|
||||||
|
|
||||||
|
This is called by the animation player after each frame.
|
||||||
|
|
||||||
|
@return true if playing should be stopped, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool prematureClose() = 0;
|
||||||
|
/*! @brief request for a mixer
|
||||||
|
|
||||||
|
This is called by the animation player when sound output is required by the animation.
|
||||||
|
|
||||||
|
@return a valid pointer to an uninitialized mixer instance, or null if none is available.
|
||||||
|
*/
|
||||||
|
virtual Mixer * getMixer() = 0;
|
||||||
|
/*! @brief debugging function : do not use
|
||||||
|
|
||||||
|
@return true if everything went fine, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool saveCurrent() { return false; };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
274
scumm/smush/saud_channel.cpp
Normal file
274
scumm/smush/saud_channel.cpp
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "channel.h"
|
||||||
|
#include "chunck.h"
|
||||||
|
#include "chunck_type.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h> // for memcpy.h
|
||||||
|
#ifndef min
|
||||||
|
#define min(x, y) ((x) > (y) ? (y) : (x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SaudChannel::handleStrk(Chunck & b) {
|
||||||
|
int size = b.getSize();
|
||||||
|
if(size != 14 && size != 10) {
|
||||||
|
error("STRK has a invalid size : %d", size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaudChannel::handleSmrk(Chunck & b) {
|
||||||
|
_markReached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaudChannel::handleShdr(Chunck & b) {
|
||||||
|
int size = b.getSize();
|
||||||
|
if(size != 4) warning("SMRK has a invalid size : %d", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaudChannel::handleSubTags(int & offset) {
|
||||||
|
int available_size = _tbufferSize - offset;
|
||||||
|
if(available_size >= 8) {
|
||||||
|
Chunck::type type = READ_BE_UINT32(_tbuffer + offset);
|
||||||
|
unsigned int size = READ_BE_UINT32(_tbuffer + offset + 4);
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case TYPE_STRK:
|
||||||
|
_inData = false;
|
||||||
|
if(available_size >= (size + 8)) {
|
||||||
|
ContChunck c((char*)_tbuffer + offset);
|
||||||
|
handleStrk(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case TYPE_SMRK:
|
||||||
|
_inData = false;
|
||||||
|
if(available_size >= (size + 8)) {
|
||||||
|
ContChunck c((char*)_tbuffer + offset);
|
||||||
|
handleSmrk(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case TYPE_SHDR:
|
||||||
|
_inData = false;
|
||||||
|
if(available_size >= (size + 8)) {
|
||||||
|
ContChunck c((char*)_tbuffer + offset);
|
||||||
|
handleShdr(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case TYPE_SDAT:
|
||||||
|
_inData = true;
|
||||||
|
_dataSize = size;
|
||||||
|
offset += 8;
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
error("unknown chunck in SAUD track : %s ", Chunck::ChunckString(type));
|
||||||
|
}
|
||||||
|
offset += size + 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaudChannel::processBuffer() {
|
||||||
|
// At the start of this function, we have _tbuffer[0.._tbuffersize] containing possible data...
|
||||||
|
// and _sbuffer is 0
|
||||||
|
// At the end we have :
|
||||||
|
// if(sound data) _sbuffer[0.._sbuffer_size] contains the sound data
|
||||||
|
// the unprocessed data is kept in _tbuffer[0.._tbuffersize] (which may have changed)
|
||||||
|
// if no unprocessed data, then _tbuffer is 0
|
||||||
|
assert(_tbuffer != 0);
|
||||||
|
assert(_tbufferSize != 0);
|
||||||
|
assert(_sbuffer == 0);
|
||||||
|
assert(_sbufferSize == 0);
|
||||||
|
|
||||||
|
if(_inData) {
|
||||||
|
if(_dataSize < _tbufferSize) {
|
||||||
|
// I can't assume that the channel is finished after data is received... (this assumption failed in realride.san)
|
||||||
|
int offset= _dataSize;
|
||||||
|
while(handleSubTags(offset));
|
||||||
|
_sbufferSize = _dataSize;
|
||||||
|
_sbuffer = _tbuffer;
|
||||||
|
if(offset < _tbufferSize) { // there is still some unprocessed data
|
||||||
|
int new_size = _tbufferSize - offset;
|
||||||
|
_tbuffer = new unsigned char[new_size];
|
||||||
|
if(!_tbuffer) error("SaudChannel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, _sbuffer + offset, new_size);
|
||||||
|
_tbufferSize = new_size;
|
||||||
|
} else {
|
||||||
|
_tbuffer = 0;
|
||||||
|
_tbufferSize = 0;
|
||||||
|
}
|
||||||
|
if(_sbufferSize == 0) {
|
||||||
|
// this never happened yet, but who knows
|
||||||
|
delete []_sbuffer;
|
||||||
|
_sbuffer = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// easy, swap the buffer
|
||||||
|
_sbufferSize = _tbufferSize;
|
||||||
|
_sbuffer = _tbuffer;
|
||||||
|
_tbufferSize = 0;
|
||||||
|
_tbuffer = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int offset = 0;
|
||||||
|
while(handleSubTags(offset));
|
||||||
|
if(_inData) {
|
||||||
|
_sbufferSize = _tbufferSize - offset;
|
||||||
|
assert(_sbufferSize);
|
||||||
|
_sbuffer = new unsigned char[_sbufferSize];
|
||||||
|
if(!_sbuffer) error("saud_channel failed to allocate memory");
|
||||||
|
memcpy(_sbuffer, _tbuffer + offset, _sbufferSize);
|
||||||
|
delete []_tbuffer;
|
||||||
|
_tbuffer = 0;
|
||||||
|
_tbufferSize = 0;
|
||||||
|
} else {
|
||||||
|
if(offset) { // maybe I should assert() this to avoid a lock...
|
||||||
|
unsigned char * old = _tbuffer;
|
||||||
|
int new_size = _tbufferSize - offset;
|
||||||
|
_tbuffer = new unsigned char[new_size];
|
||||||
|
if(!_tbuffer) error("SaudChannel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, old + offset, new_size);
|
||||||
|
_tbufferSize = new_size;
|
||||||
|
delete []old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaudChannel::SaudChannel(int track, int freq) :
|
||||||
|
_track(track),
|
||||||
|
_nbframes(0),
|
||||||
|
_dataSize(-1),
|
||||||
|
_tbuffer(0),
|
||||||
|
_sbuffer(0),
|
||||||
|
_frequency(freq),
|
||||||
|
_tbufferSize(0),
|
||||||
|
_sbufferSize(0),
|
||||||
|
_inData(false),
|
||||||
|
_markReached(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SaudChannel::~SaudChannel() {
|
||||||
|
if(_tbuffer) delete []_tbuffer;
|
||||||
|
if(_sbuffer) {
|
||||||
|
warning("this should never happen !!!! (_sbuffer not NULL here)");
|
||||||
|
delete []_sbuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaudChannel::isTerminated() const {
|
||||||
|
return (_markReached && _dataSize == 0 && _sbuffer == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaudChannel::recalcVolumeTable() {
|
||||||
|
const int MAX_BALANCE = 100;
|
||||||
|
int volume_left, volume_right;
|
||||||
|
if(_balance < -MAX_BALANCE || _balance > MAX_BALANCE) {
|
||||||
|
error("balance is out of range ! : %d", _balance);
|
||||||
|
}
|
||||||
|
int left_multiplier = MAX_BALANCE - _balance;
|
||||||
|
int right_multiplier = MAX_BALANCE + _balance;
|
||||||
|
volume_left = _volume * left_multiplier / (MAX_BALANCE * 2);
|
||||||
|
volume_right = _volume * right_multiplier / (MAX_BALANCE * 2);
|
||||||
|
if(volume_left < 0) volume_left = 0;
|
||||||
|
if(volume_left > 128) volume_left = 128;
|
||||||
|
if(volume_right < 0) volume_right = 0;
|
||||||
|
if(volume_right > 128) volume_right = 128;
|
||||||
|
for(int i = 0; i < 256; i++) {
|
||||||
|
int value = volume_left * (signed char)i;
|
||||||
|
_voltable[0][i] = TO_BE_16(value);
|
||||||
|
value = volume_right * (signed char)i;
|
||||||
|
_voltable[1][i] = TO_BE_16(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaudChannel::setParameters(int nb, int flags, int volume, int balance) {
|
||||||
|
_nbframes = nb;
|
||||||
|
_flags = flags; // bit 7 == IS_VOICE, bit 6 == IS_BACKGROUND_MUSIC, other ??
|
||||||
|
_volume = volume;
|
||||||
|
_balance = balance;
|
||||||
|
_index = 0;
|
||||||
|
recalcVolumeTable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaudChannel::checkParameters(int index, int nb, int flags, int volume, int balance) {
|
||||||
|
if(++_index != index) error("invalid index in SaudChannel::checkParameters()");
|
||||||
|
if(_nbframes != nb) error("invalid duration in SaudChannel::checkParameters()");
|
||||||
|
if(_flags != flags) error("invalid flags in SaudChannel::checkParameters()");
|
||||||
|
if(_volume != volume || _balance != balance) {
|
||||||
|
_volume = volume;
|
||||||
|
_balance = balance;
|
||||||
|
recalcVolumeTable();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaudChannel::appendData(Chunck & b, int size) {
|
||||||
|
if(_dataSize == -1) { // First call
|
||||||
|
assert(size > 8);
|
||||||
|
Chunck::type saud_type = b.getDword(); saud_type = TO_BE_32(saud_type);
|
||||||
|
unsigned int saud_size = b.getDword(); saud_size = TO_BE_32(saud_size);
|
||||||
|
if(saud_type != TYPE_SAUD) error("Invalid CHUNCK for SaudChannel : %X", saud_type);
|
||||||
|
size -= 8;
|
||||||
|
_dataSize = -2; // We don't get here again...
|
||||||
|
}
|
||||||
|
if(_tbuffer) {
|
||||||
|
unsigned char * old = _tbuffer;
|
||||||
|
_tbuffer = new unsigned char[_tbufferSize + size];
|
||||||
|
if(!_tbuffer) error("saud_channel failed to allocate memory");
|
||||||
|
memcpy(_tbuffer, old, _tbufferSize);
|
||||||
|
delete []old;
|
||||||
|
b.read(_tbuffer + _tbufferSize, size);
|
||||||
|
_tbufferSize += size;
|
||||||
|
} else {
|
||||||
|
_tbufferSize = size;
|
||||||
|
_tbuffer = new unsigned char[_tbufferSize];
|
||||||
|
if(!_tbuffer) error("saud_channel failed to allocate memory");
|
||||||
|
b.read(_tbuffer, _tbufferSize);
|
||||||
|
}
|
||||||
|
return processBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SaudChannel::availableSoundData(void) const {
|
||||||
|
return _sbufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaudChannel::getSoundData(short * snd, int size) {
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
snd[2 * i] = _voltable[0][_sbuffer[i] ^ 0x80];
|
||||||
|
snd[2 * i + 1] = _voltable[1][_sbuffer[i] ^ 0x80];
|
||||||
|
}
|
||||||
|
_dataSize -= size;
|
||||||
|
delete []_sbuffer;
|
||||||
|
_sbuffer = 0;
|
||||||
|
_sbufferSize = 0;
|
||||||
|
}
|
266
scumm/smush/scumm_renderer.cpp
Normal file
266
scumm/smush/scumm_renderer.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdafx.h>
|
||||||
|
#include "scumm_renderer.h"
|
||||||
|
#include "channel.h"
|
||||||
|
|
||||||
|
class scumm_mixer : public Mixer {
|
||||||
|
private:
|
||||||
|
SoundMixer * _mixer; //!< pointer to the SoundMixer instance
|
||||||
|
struct {
|
||||||
|
int id;
|
||||||
|
_Channel * chan;
|
||||||
|
bool first;
|
||||||
|
int mixer_index;
|
||||||
|
} _channels[SoundMixer::NUM_CHANNELS]; //!< The map of track and channels
|
||||||
|
int _nextIndex;
|
||||||
|
public:
|
||||||
|
scumm_mixer(SoundMixer *);
|
||||||
|
virtual ~scumm_mixer();
|
||||||
|
bool init();
|
||||||
|
_Channel * findChannel(int track);
|
||||||
|
bool addChannel(_Channel * c);
|
||||||
|
bool handleFrame();
|
||||||
|
bool stop();
|
||||||
|
bool update();
|
||||||
|
};
|
||||||
|
|
||||||
|
scumm_mixer::scumm_mixer(SoundMixer * m) : _mixer(m), _nextIndex(0) {
|
||||||
|
for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
_channels[i].id = -1;
|
||||||
|
_channels[i].chan = 0;
|
||||||
|
_channels[i].first = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scumm_mixer::~scumm_mixer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool scumm_mixer::init() {
|
||||||
|
debug(9, "scumm_mixer::init()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Channel * scumm_mixer::findChannel(int track) {
|
||||||
|
debug(9, "scumm_mixer::findChannel(%d)", track);
|
||||||
|
for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
if(_channels[i].id == track)
|
||||||
|
return _channels[i].chan;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool scumm_mixer::addChannel(_Channel * c) {
|
||||||
|
int track = c->getTrackIdentifier();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
debug(9, "scumm_mixer::addChannel(%d)", track);
|
||||||
|
|
||||||
|
for(i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
if(_channels[i].id == track)
|
||||||
|
warning("mixer::addChannel(%d) : channel already exist !", track);
|
||||||
|
}
|
||||||
|
if(_nextIndex >= SoundMixer::NUM_CHANNELS) _nextIndex = 0;
|
||||||
|
|
||||||
|
for(i = _nextIndex; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
if(_channels[i].chan == 0 || _channels[i].id == -1) {
|
||||||
|
_channels[i].chan = c;
|
||||||
|
_channels[i].id = track;
|
||||||
|
_channels[i].first = true;
|
||||||
|
_nextIndex = i + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < _nextIndex; i++) {
|
||||||
|
if(_channels[i].chan == 0 || _channels[i].id == -1) {
|
||||||
|
_channels[i].chan = c;
|
||||||
|
_channels[i].id = track;
|
||||||
|
_channels[i].first = true;
|
||||||
|
_nextIndex = i + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "_nextIndex == %d\n", _nextIndex);
|
||||||
|
|
||||||
|
for(i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
fprintf(stderr, "channel %d : %p(%d, %d) %d %d\n", i, _channels[i].chan,
|
||||||
|
_channels[i].chan ? _channels[i].chan->getTrackIdentifier() : -1,
|
||||||
|
_channels[i].chan ? _channels[i].chan->isTerminated() : 1,
|
||||||
|
_channels[i].first, _channels[i].mixer_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
error("mixer::add_channel() : no more channel available");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool scumm_mixer::handleFrame() {
|
||||||
|
debug(9, "scumm_mixer::handleFrame()");
|
||||||
|
for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
if(_channels[i].id != -1) {
|
||||||
|
debug(9, "updating channel %d (%p)", _channels[i].id, _channels[i].chan);
|
||||||
|
if(_channels[i].chan->isTerminated()) {
|
||||||
|
debug(9, "channel %d has terminated (%p)", _channels[i].id, _channels[i].chan);
|
||||||
|
delete _channels[i].chan;
|
||||||
|
_channels[i].id = -1;
|
||||||
|
_channels[i].chan = 0;
|
||||||
|
} else {
|
||||||
|
int rate;
|
||||||
|
bool stereo, is_short;
|
||||||
|
|
||||||
|
_channels[i].chan->getParameters(rate, stereo, is_short);
|
||||||
|
int size = _channels[i].chan->availableSoundData();
|
||||||
|
debug(9, "channel %d : %d, %s, %d bits, %d", _channels[i].id, rate, stereo ? "stereo" : "mono", is_short ? 16 : 8, size);
|
||||||
|
int flags = stereo ? SoundMixer::FLAG_STEREO : 0;
|
||||||
|
|
||||||
|
if(is_short) {
|
||||||
|
// FIXME this is one more data copy... we could get rid of it...
|
||||||
|
short * data = new short[size * (stereo ? 2 : 1)];
|
||||||
|
_channels[i].chan->getSoundData(data, size);
|
||||||
|
size *= stereo ? 4 : 2;
|
||||||
|
|
||||||
|
// append to _sound
|
||||||
|
if(_channels[i].first) {
|
||||||
|
_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_16BITS);
|
||||||
|
debug(5, "channel %d bound to mixer_index %d", _channels[i].id, _channels[i].mixer_index);
|
||||||
|
_channels[i].first = false;
|
||||||
|
} else {
|
||||||
|
_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_16BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete []data;
|
||||||
|
} else {
|
||||||
|
char * data = new char[size*(stereo ? 2 : 1)];
|
||||||
|
_channels[i].chan->getSoundData(data, size);
|
||||||
|
size *= stereo ? 2 : 1;
|
||||||
|
|
||||||
|
// append to _sound
|
||||||
|
if(_channels[i].first) {
|
||||||
|
_channels[i].mixer_index = _mixer->playStream(NULL, -1, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED);
|
||||||
|
_channels[i].first = false;
|
||||||
|
} else {
|
||||||
|
_mixer->append(_channels[i].mixer_index, data, size, rate, flags | SoundMixer::FLAG_UNSIGNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete []data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool scumm_mixer::stop() {
|
||||||
|
debug(9, "scumm_mixer::stop()");
|
||||||
|
for(int i = 0; i < SoundMixer::NUM_CHANNELS; i++) {
|
||||||
|
if(_channels[i].id != -1) {
|
||||||
|
delete _channels[i].chan;
|
||||||
|
_channels[i].id = -1;
|
||||||
|
_channels[i].chan = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//~ _mixer->stopAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScummRenderer::ScummRenderer(Scumm * scumm) : _scumm(scumm), _smixer(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static ScummRenderer * s_renderer;
|
||||||
|
|
||||||
|
static void smush_handler(Scumm * scumm) {
|
||||||
|
s_renderer->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Mixer * ScummRenderer::getMixer() {
|
||||||
|
if(_smixer == 0) {
|
||||||
|
_scumm->_sound->pauseBundleMusic(true);
|
||||||
|
_smixer = new scumm_mixer(_scumm->_mixer);
|
||||||
|
if(!_smixer) error("unable to allocate a smush mixer");
|
||||||
|
s_renderer = this;
|
||||||
|
_scumm->_timer->installProcedure(&smush_handler, 75);
|
||||||
|
}
|
||||||
|
return _smixer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScummRenderer::~ScummRenderer() {
|
||||||
|
_scumm->_insaneState = 0;
|
||||||
|
_scumm->exitCutscene();
|
||||||
|
if(_smixer) {
|
||||||
|
_scumm->_timer->releaseProcedure(&smush_handler);
|
||||||
|
delete _smixer;
|
||||||
|
_smixer = 0;
|
||||||
|
}
|
||||||
|
_scumm->_sound->pauseBundleMusic(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScummRenderer::wait(int ms) {
|
||||||
|
while(_wait) {
|
||||||
|
_scumm->waitForTimer(1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScummRenderer::startDecode(const char * fname, int version, int nbframes) {
|
||||||
|
_scumm->_sound->pauseBundleMusic(true);
|
||||||
|
_scumm->videoFinished = 0;
|
||||||
|
_scumm->_insaneState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScummRenderer::setPalette(const Palette & pal) {
|
||||||
|
int i;
|
||||||
|
byte palette_colors[1024];
|
||||||
|
byte *p = palette_colors;
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++, p += 4) {
|
||||||
|
p[0] = pal[i].red();
|
||||||
|
p[1] = pal[i].green();
|
||||||
|
p[2] = pal[i].blue();
|
||||||
|
p[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_scumm->_system->set_palette(palette_colors, 0, 256);
|
||||||
|
_scumm->setDirtyColors(0, 255);
|
||||||
|
return BaseRenderer::setPalette(pal); // For compatibility with possible subclass...
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScummRenderer::save(int frame) {
|
||||||
|
int width = min(getWidth(), _scumm->_realWidth);
|
||||||
|
int height = min(getHeight(), _scumm->_realHeight);
|
||||||
|
|
||||||
|
_scumm->_system->copy_rect((const byte *)data(), getWidth(), 0, 0, width, height);
|
||||||
|
_scumm->_system->update_screen();
|
||||||
|
_scumm->processKbd();
|
||||||
|
_wait = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScummRenderer::prematureClose() {
|
||||||
|
return _scumm->videoFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScummRenderer::update() {
|
||||||
|
_wait = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
66
scumm/smush/scumm_renderer.h
Normal file
66
scumm/smush/scumm_renderer.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001/2002 The ScummVM project
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SCUMM_RENDERER_H_
|
||||||
|
#define __SCUMM_RENDERER_H_
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef NO_DEBUG_SCUMM_RENDERER
|
||||||
|
# define DEBUG_SCUMM_RENDERER
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifdef DEBUG_SCUMM_RENDERER
|
||||||
|
# error DEBUG_SCUMM_RENDERER defined without DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "brenderer.h"
|
||||||
|
#include "mixer.h"
|
||||||
|
#include "rect.h"
|
||||||
|
#include "blitter.h"
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(x, y) ((x) > (y) ? (y) : (x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class scumm_mixer;
|
||||||
|
|
||||||
|
class ScummRenderer : public BaseRenderer {
|
||||||
|
private:
|
||||||
|
Scumm * _scumm;
|
||||||
|
scumm_mixer * _smixer;
|
||||||
|
volatile bool _wait;
|
||||||
|
public:
|
||||||
|
ScummRenderer(Scumm * scumm);
|
||||||
|
virtual ~ScummRenderer();
|
||||||
|
virtual bool wait(int ms);
|
||||||
|
bool update();
|
||||||
|
protected:
|
||||||
|
virtual bool startDecode(const char * fname, int version, int nbframes);
|
||||||
|
virtual bool setPalette(const Palette & pal);
|
||||||
|
virtual void save(int frame = -1);
|
||||||
|
virtual Mixer * getMixer();
|
||||||
|
virtual bool prematureClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -128,7 +128,7 @@ SimonState::SimonState(GameDetector *detector, OSystem *syst)
|
||||||
_game = detector->_gameId;
|
_game = detector->_gameId;
|
||||||
|
|
||||||
/* Setup mixer */
|
/* Setup mixer */
|
||||||
if (!_mixer->bind_to_system(syst))
|
if (!_mixer->bindToSystem(syst))
|
||||||
warning("Sound initialization failed. "
|
warning("Sound initialization failed. "
|
||||||
"Features of the game that depend on sound synchronization will most likely break");
|
"Features of the game that depend on sound synchronization will most likely break");
|
||||||
set_volume(detector->_sfx_volume);
|
set_volume(detector->_sfx_volume);
|
||||||
|
@ -3296,7 +3296,7 @@ void SimonState::readSfxFile(const char *filename)
|
||||||
fseek(in, 0, SEEK_SET);
|
fseek(in, 0, SEEK_SET);
|
||||||
|
|
||||||
/* stop all sounds */
|
/* stop all sounds */
|
||||||
_mixer->stop_all();
|
_mixer->stopAll();
|
||||||
|
|
||||||
if (_sfx_heap)
|
if (_sfx_heap)
|
||||||
free(_sfx_heap);
|
free(_sfx_heap);
|
||||||
|
@ -4038,7 +4038,6 @@ void SimonState::read_vga_from_datfile_1(uint vga_id)
|
||||||
FILE *in;
|
FILE *in;
|
||||||
char buf[50];
|
char buf[50];
|
||||||
uint32 size;
|
uint32 size;
|
||||||
|
|
||||||
// FIXME - weird hack to make the beard show up when wearing it (see bug #590800)
|
// FIXME - weird hack to make the beard show up when wearing it (see bug #590800)
|
||||||
if (vga_id == 328)
|
if (vga_id == 328)
|
||||||
sprintf(buf, "0119.VGA");
|
sprintf(buf, "0119.VGA");
|
||||||
|
@ -4798,7 +4797,7 @@ void SimonState::playVoice(uint voice)
|
||||||
byte *buffer = (byte *)malloc(data[1]);
|
byte *buffer = (byte *)malloc(data[1]);
|
||||||
fread(buffer, data[1], 1, _voice_file);
|
fread(buffer, data[1], 1, _voice_file);
|
||||||
|
|
||||||
_mixer->play_raw(&_voice_sound, buffer, data[1], READ_LE_UINT32(&wave_hdr.samples_per_sec),
|
_mixer->playRaw(&_voice_sound, buffer, data[1], READ_LE_UINT32(&wave_hdr.samples_per_sec),
|
||||||
SoundMixer::FLAG_UNSIGNED);
|
SoundMixer::FLAG_UNSIGNED);
|
||||||
} else { /* VOC audio */
|
} else { /* VOC audio */
|
||||||
VocHeader voc_hdr;
|
VocHeader voc_hdr;
|
||||||
|
@ -4821,7 +4820,7 @@ void SimonState::playVoice(uint voice)
|
||||||
byte *buffer = (byte *)malloc(size);
|
byte *buffer = (byte *)malloc(size);
|
||||||
fread(buffer, size, 1, _voice_file);
|
fread(buffer, size, 1, _voice_file);
|
||||||
|
|
||||||
_mixer->play_raw(&_voice_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED);
|
_mixer->playRaw(&_voice_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4854,7 +4853,7 @@ void SimonState::playSound(uint sound)
|
||||||
byte *buffer = (byte *)malloc(size);
|
byte *buffer = (byte *)malloc(size);
|
||||||
fread(buffer, size, 1, _effects_file);
|
fread(buffer, size, 1, _effects_file);
|
||||||
|
|
||||||
_mixer->play_raw(&_effects_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED);
|
_mixer->playRaw(&_effects_sound, buffer, size, samples_per_sec, SoundMixer::FLAG_UNSIGNED);
|
||||||
} else {
|
} else {
|
||||||
byte *p;
|
byte *p;
|
||||||
|
|
||||||
|
@ -4880,7 +4879,7 @@ void SimonState::playSound(uint sound)
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mixer->play_raw(&_playing_sound, p + 8, READ_LE_UINT32(p + 4), 22050,
|
_mixer->playRaw(&_playing_sound, p + 8, READ_LE_UINT32(p + 4), 22050,
|
||||||
SoundMixer::FLAG_UNSIGNED);
|
SoundMixer::FLAG_UNSIGNED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -4938,7 +4937,7 @@ void SimonState::dx_unlock_attached()
|
||||||
|
|
||||||
void SimonState::set_volume(byte volume)
|
void SimonState::set_volume(byte volume)
|
||||||
{
|
{
|
||||||
_mixer->set_volume(volume);
|
_mixer->setVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1367,7 +1367,7 @@ void SimonState::vc_28()
|
||||||
|
|
||||||
void SimonState::vc_29_stop_all_sounds()
|
void SimonState::vc_29_stop_all_sounds()
|
||||||
{
|
{
|
||||||
_mixer->stop_all();
|
_mixer->stopAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimonState::vc_30_set_base_delay()
|
void SimonState::vc_30_set_base_delay()
|
||||||
|
|
|
@ -1075,7 +1075,7 @@ MidiDriver_MIDIEMU::MidiDriver_MIDIEMU()
|
||||||
int MidiDriver_MIDIEMU::open(int mode)
|
int MidiDriver_MIDIEMU::open(int mode)
|
||||||
{
|
{
|
||||||
_opl = OPLCreate(OPL_TYPE_YM3812, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0));
|
_opl = OPLCreate(OPL_TYPE_YM3812, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0));
|
||||||
g_mixer->setup_premix((void *)this, premix_proc);
|
g_mixer->setupPremix((void *)this, premix_proc);
|
||||||
if (_stream_proc)
|
if (_stream_proc)
|
||||||
g_system->create_thread(midiemu_callback_thread, this);
|
g_system->create_thread(midiemu_callback_thread, this);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
449
sound/mixer.cpp
449
sound/mixer.cpp
|
@ -23,19 +23,15 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "scumm.h"
|
#include "scumm.h"
|
||||||
|
|
||||||
SoundMixer::SoundMixer()
|
SoundMixer::SoundMixer() {
|
||||||
{
|
_volumeTable = (int16 *)calloc(256 * sizeof(int16), 1);
|
||||||
_volume_table = (int16 *)calloc(256 * sizeof(int16), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundMixer::~SoundMixer()
|
SoundMixer::~SoundMixer() {
|
||||||
{
|
free(_volumeTable);
|
||||||
free(_volume_table);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::uninsert(Channel * chan)
|
void SoundMixer::unInsert(Channel * chan) {
|
||||||
{
|
|
||||||
|
|
||||||
for (int i = 0; i != NUM_CHANNELS; i++) {
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
||||||
if (_channels[i] == chan) {
|
if (_channels[i] == chan) {
|
||||||
if (_handles[i]) {
|
if (_handles[i]) {
|
||||||
|
@ -49,14 +45,13 @@ void SoundMixer::uninsert(Channel * chan)
|
||||||
error("SoundMixer::channel_deleted chan not found");
|
error("SoundMixer::channel_deleted chan not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
int SoundMixer::append(int index, void *sound, uint32 size, uint rate, byte flags)
|
int SoundMixer::append(int index, void * sound, uint32 size, uint rate, byte flags) {
|
||||||
{
|
|
||||||
_syst->lock_mutex(_mutex);
|
_syst->lock_mutex(_mutex);
|
||||||
|
|
||||||
Channel *chan = _channels[index];
|
Channel * chan = _channels[index];
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
warning("Trying to stream to an unexistant streamer ");
|
warning("Trying to stream to an unexistant streamer : %d", index);
|
||||||
play_stream(NULL, index, sound, size, rate, flags);
|
playStream(NULL, index, sound, size, rate, flags);
|
||||||
chan = _channels[index];
|
chan = _channels[index];
|
||||||
} else {
|
} else {
|
||||||
chan->append(sound, size);
|
chan->append(sound, size);
|
||||||
|
@ -68,8 +63,15 @@ int SoundMixer::append(int index, void *sound, uint32 size, uint rate, byte flag
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SoundMixer::insert_at(PlayingSoundHandle *handle, int index, Channel * chan)
|
int SoundMixer::insertAt(PlayingSoundHandle * handle, int index, Channel * chan) {
|
||||||
{
|
if(index == -1) {
|
||||||
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
||||||
|
if (_channels[i] == NULL) { index = i; break; }
|
||||||
|
if(index == -1) {
|
||||||
|
warning("SoundMixer::out of mixer slots");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (_channels[index] != NULL) {
|
if (_channels[index] != NULL) {
|
||||||
error("Trying to put a mixer where it cannot go ");
|
error("Trying to put a mixer where it cannot go ");
|
||||||
}
|
}
|
||||||
|
@ -80,12 +82,11 @@ int SoundMixer::insert_at(PlayingSoundHandle *handle, int index, Channel * chan)
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SoundMixer::play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate,
|
int SoundMixer::playRaw(PlayingSoundHandle * handle, void * sound, uint32 size, uint rate,
|
||||||
byte flags)
|
byte flags) {
|
||||||
{
|
|
||||||
for (int i = 0; i != NUM_CHANNELS; i++) {
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
||||||
if (_channels[i] == NULL) {
|
if (_channels[i] == NULL) {
|
||||||
return insert_at(handle, i, new Channel_RAW(this, sound, size, rate, flags));
|
return insertAt(handle, i, new ChannelRaw(this, sound, size, rate, flags));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,30 +94,27 @@ int SoundMixer::play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, u
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SoundMixer::play_stream(PlayingSoundHandle *handle, int idx, void *sound, uint32 size,
|
int SoundMixer::playStream(PlayingSoundHandle * handle, int idx, void * sound, uint32 size,
|
||||||
uint rate, byte flags)
|
uint rate, byte flags) {
|
||||||
{
|
return insertAt(handle, idx, new ChannelStream(this, sound, size, rate, flags));
|
||||||
return insert_at(handle, idx, new Channel_STREAM(this, sound, size, rate, flags));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
int SoundMixer::play_mp3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags)
|
int SoundMixer::playMP3(PlayingSoundHandle * handle, void *sound, uint32 size, byte flags) {
|
||||||
{
|
|
||||||
for (int i = 0; i != NUM_CHANNELS; i++) {
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
||||||
if (_channels[i] == NULL) {
|
if (_channels[i] == NULL) {
|
||||||
return insert_at(handle, i, new Channel_MP3(this, sound, size, flags));
|
return insertAt(handle, i, new ChannelMP3(this, sound, size, flags));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
warning("SoundMixer::out of mixer slots");
|
warning("SoundMixer::out of mixer slots");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int SoundMixer::play_mp3_cdtrack(PlayingSoundHandle *handle, FILE * file, mad_timer_t duration)
|
int SoundMixer::playMP3CDTrack(PlayingSoundHandle * handle, FILE * file, mad_timer_t duration) {
|
||||||
{
|
|
||||||
/* Stop the previously playing CD track (if any) */
|
/* Stop the previously playing CD track (if any) */
|
||||||
for (int i = 0; i != NUM_CHANNELS; i++) {
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
||||||
if (_channels[i] == NULL) {
|
if (_channels[i] == NULL) {
|
||||||
return insert_at(handle, i, new Channel_MP3_CDMUSIC(this, file, duration));
|
return insertAt(handle, i, new ChannelMP3CDMusic(this, file, duration));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,16 +123,15 @@ int SoundMixer::play_mp3_cdtrack(PlayingSoundHandle *handle, FILE * file, mad_ti
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SoundMixer::mix(int16 *buf, uint len)
|
void SoundMixer::mix(int16 *buf, uint len) {
|
||||||
{
|
|
||||||
if (_paused) {
|
if (_paused) {
|
||||||
memset(buf, 0, 2 * len * sizeof(int16));
|
memset(buf, 0, 2 * len * sizeof(int16));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_premix_proc) {
|
if (_premixProc) {
|
||||||
int i;
|
int i;
|
||||||
_premix_proc(_premix_param, buf, len);
|
_premixProc(_premixParam, buf, len);
|
||||||
for (i = (len - 1); i >= 0; i--) {
|
for (i = (len - 1); i >= 0; i--) {
|
||||||
buf[2 * i] = buf[2 * i + 1] = buf[i];
|
buf[2 * i] = buf[2 * i + 1] = buf[i];
|
||||||
}
|
}
|
||||||
|
@ -151,16 +148,14 @@ void SoundMixer::mix(int16 *buf, uint len)
|
||||||
_syst->unlock_mutex(_mutex);
|
_syst->unlock_mutex(_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::on_generate_samples(void *s, byte *samples, int len)
|
void SoundMixer::onGenerateSamples(void * s, byte * samples, int len) {
|
||||||
{
|
|
||||||
((SoundMixer *)s)->mix((int16 *)samples, len >> 2);
|
((SoundMixer *)s)->mix((int16 *)samples, len >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundMixer::bind_to_system(OSystem *syst)
|
bool SoundMixer::bindToSystem(OSystem * syst) {
|
||||||
{
|
|
||||||
uint rate = (uint) syst->property(OSystem::PROP_GET_SAMPLE_RATE, 0);
|
uint rate = (uint) syst->property(OSystem::PROP_GET_SAMPLE_RATE, 0);
|
||||||
|
|
||||||
_output_rate = rate;
|
_outputRate = rate;
|
||||||
|
|
||||||
_syst = syst;
|
_syst = syst;
|
||||||
_mutex = _syst->create_mutex();
|
_mutex = _syst->create_mutex();
|
||||||
|
@ -168,49 +163,42 @@ bool SoundMixer::bind_to_system(OSystem *syst)
|
||||||
if (rate == 0)
|
if (rate == 0)
|
||||||
error("OSystem returned invalid sample rate");
|
error("OSystem returned invalid sample rate");
|
||||||
|
|
||||||
return syst->set_sound_proc(this, on_generate_samples, OSystem::SOUND_16BIT);
|
return syst->set_sound_proc(this, onGenerateSamples, OSystem::SOUND_16BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::stop_all()
|
void SoundMixer::stopAll() {
|
||||||
{
|
|
||||||
for (int i = 0; i != NUM_CHANNELS; i++)
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
||||||
if (_channels[i])
|
if (_channels[i])
|
||||||
_channels[i]->destroy();
|
_channels[i]->destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::stop(PlayingSoundHandle psh)
|
void SoundMixer::stop(PlayingSoundHandle psh) {
|
||||||
{
|
|
||||||
if (psh && _channels[psh - 1])
|
if (psh && _channels[psh - 1])
|
||||||
_channels[psh - 1]->destroy();
|
_channels[psh - 1]->destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::stop(int index)
|
void SoundMixer::stop(int index) {
|
||||||
{
|
|
||||||
if (_channels[index])
|
if (_channels[index])
|
||||||
_channels[index]->destroy();
|
_channels[index]->destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::pause(bool paused)
|
void SoundMixer::pause(bool paused) {
|
||||||
{
|
|
||||||
_paused = paused;
|
_paused = paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundMixer::has_active_channel()
|
bool SoundMixer::hasActiveChannel() {
|
||||||
{
|
|
||||||
for (int i = 0; i != NUM_CHANNELS; i++)
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
||||||
if (_channels[i])
|
if (_channels[i])
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::setup_premix(void *param, PremixProc *proc)
|
void SoundMixer::setupPremix(void * param, PremixProc * proc) {
|
||||||
{
|
_premixParam = param;
|
||||||
_premix_param = param;
|
_premixProc = proc;
|
||||||
_premix_proc = proc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::set_volume(int volume)
|
void SoundMixer::setVolume(int volume) {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Check range
|
// Check range
|
||||||
|
@ -221,55 +209,51 @@ void SoundMixer::set_volume(int volume)
|
||||||
|
|
||||||
// The volume table takes 8 bit unsigned data as index and returns 16 bit signed
|
// The volume table takes 8 bit unsigned data as index and returns 16 bit signed
|
||||||
for (i = 0; i < 128; i++)
|
for (i = 0; i < 128; i++)
|
||||||
_volume_table[i] = i * volume;
|
_volumeTable[i] = i * volume;
|
||||||
|
|
||||||
for (i = -128; i < 0; i++)
|
for (i = -128; i < 0; i++)
|
||||||
_volume_table[i+256] = i * volume;
|
_volumeTable[i + 256] = i * volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::set_music_volume(int volume)
|
void SoundMixer::setMusicVolume(int volume) {
|
||||||
{
|
|
||||||
// Check range
|
// Check range
|
||||||
if (volume > 256)
|
if (volume > 256)
|
||||||
volume = 256;
|
volume = 256;
|
||||||
else if (volume < 0)
|
else if (volume < 0)
|
||||||
volume = 0;
|
volume = 0;
|
||||||
|
|
||||||
_music_volume = volume;
|
_musicVolume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
bool SoundMixer::Channel::sound_finished()
|
bool SoundMixer::Channel::soundFinished() {
|
||||||
{
|
|
||||||
warning("sound_finished should never be called on a non-MP3 mixer ");
|
warning("sound_finished should never be called on a non-MP3 mixer ");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SoundMixer::Channel::append(void *sound, uint32 size)
|
void SoundMixer::Channel::append(void * sound, uint32 size) {
|
||||||
{
|
|
||||||
error("append method should never be called on something else than a _STREAM mixer ");
|
error("append method should never be called on something else than a _STREAM mixer ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RAW mixer */
|
/* RAW mixer */
|
||||||
SoundMixer::Channel_RAW::Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate,
|
SoundMixer::ChannelRaw::ChannelRaw(SoundMixer * mixer, void * sound, uint32 size, uint rate,
|
||||||
byte flags)
|
byte flags) {
|
||||||
{
|
|
||||||
_mixer = mixer;
|
_mixer = mixer;
|
||||||
_flags = flags;
|
_flags = flags;
|
||||||
_ptr = sound;
|
_ptr = sound;
|
||||||
_pos = 0;
|
_pos = 0;
|
||||||
_fp_pos = 0;
|
_fpPos = 0;
|
||||||
_fp_speed = (1 << 16) * rate / mixer->_output_rate;
|
_fpSpeed = (1 << 16) * rate / mixer->_outputRate;
|
||||||
_to_be_destroyed = false;
|
_toBeDestroyed = false;
|
||||||
_realsize = size;
|
_realSize = size;
|
||||||
|
|
||||||
// adjust the magnitude to prevent division error
|
// adjust the magnitude to prevent division error
|
||||||
while (size & 0xFFFF0000)
|
while (size & 0xFFFF0000)
|
||||||
size >>= 1, rate = (rate >> 1) + 1;
|
size >>= 1, rate = (rate >> 1) + 1;
|
||||||
|
|
||||||
_rate = rate;
|
_rate = rate;
|
||||||
_size = size * mixer->_output_rate / rate;
|
_size = size * mixer->_outputRate / rate;
|
||||||
if (_flags & FLAG_16BITS)
|
if (_flags & FLAG_16BITS)
|
||||||
_size = _size >> 1;
|
_size = _size >> 1;
|
||||||
if (_flags & FLAG_STEREO)
|
if (_flags & FLAG_STEREO)
|
||||||
|
@ -288,7 +272,7 @@ protected:
|
||||||
int a, b, c, d;
|
int a, b, c, d;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CubicInterpolator(int a, int b, int c) : x0(2*a-b), x1(a), x2(b), x3(c)
|
CubicInterpolator(int a, int b, int c) : x0(2 * a - b), x1(a), x2(b), x3(c)
|
||||||
{
|
{
|
||||||
// We use a simple linear interpolation for x0
|
// We use a simple linear interpolation for x0
|
||||||
updateCoefficients();
|
updateCoefficients();
|
||||||
|
@ -299,7 +283,7 @@ public:
|
||||||
x0 = x1;
|
x0 = x1;
|
||||||
x1 = x2;
|
x1 = x2;
|
||||||
x2 = x3;
|
x2 = x3;
|
||||||
x3 = 2*x2-x1; // Simple linear interpolation
|
x3 = 2 * x2 - x1; // Simple linear interpolation
|
||||||
updateCoefficients();
|
updateCoefficients();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,14 +297,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* t must be a 16.16 fixed point number between 0 and 1 */
|
/* t must be a 16.16 fixed point number between 0 and 1 */
|
||||||
inline int interpolate(uint32 fp_pos)
|
inline int interpolate(uint32 fpPos)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int t = fp_pos >> 8;
|
int t = fpPos >> 8;
|
||||||
result = (a*t + b) >> 8;
|
result = (a * t + b) >> 8;
|
||||||
result = (result * t + c) >> 8;
|
result = (result * t + c) >> 8;
|
||||||
result = (result * t + d) >> 8;
|
result = (result * t + d) >> 8;
|
||||||
result = (result/3 + 1) >> 1;
|
result = (result / 3 + 1) >> 1;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -328,15 +312,14 @@ public:
|
||||||
protected:
|
protected:
|
||||||
inline void updateCoefficients()
|
inline void updateCoefficients()
|
||||||
{
|
{
|
||||||
a = ((-x0*2)+(x1*5)-(x2*4)+x3);
|
a = ((-x0 * 2) + (x1 * 5) - (x2 * 4) + x3);
|
||||||
b = ((x0+x2-(2*x1))*6) << 8;
|
b = ((x0 + x2 - (2 * x1)) * 6) << 8;
|
||||||
c = ((-4*x0)+x1+(x2*4)-x3) << 8;
|
c = ((-4 * x0) + x1 + (x2 * 4) - x3) << 8;
|
||||||
d = (x1*6) << 8;
|
d = (x1 * 6) << 8;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int clamped_add_16(int a, int b)
|
static inline int clamped_add_16(int a, int b) {
|
||||||
{
|
|
||||||
int val = a + b;
|
int val = a + b;
|
||||||
|
|
||||||
if (val > 32767) {
|
if (val > 32767) {
|
||||||
|
@ -347,15 +330,14 @@ static inline int clamped_add_16(int a, int b)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16 *mix_signed_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
static int16 * mix_signed_mono_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
{
|
|
||||||
uint32 fp_pos = *fp_pos_ptr;
|
uint32 fp_pos = *fp_pos_ptr;
|
||||||
byte *s = *s_ptr;
|
byte *s = *s_ptr;
|
||||||
uint len = *len_ptr;
|
uint len = *len_ptr;
|
||||||
|
|
||||||
int inc = 1, result;
|
int inc = 1, result;
|
||||||
CubicInterpolator interp(vol_tab[*s], vol_tab[*(s+1)], vol_tab[*(s+2)]);
|
CubicInterpolator interp(vol_tab[*s], vol_tab[*(s + 1)], vol_tab[*(s + 2)]);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
|
@ -373,8 +355,8 @@ static int16 *mix_signed_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint3
|
||||||
fp_pos &= 0x0000FFFF;
|
fp_pos &= 0x0000FFFF;
|
||||||
} while (!inc && len && (s < s_end));
|
} while (!inc && len && (s < s_end));
|
||||||
|
|
||||||
if (s+2 < s_end)
|
if (s + 2 < s_end)
|
||||||
interp.feedData(vol_tab[*(s+2)]);
|
interp.feedData(vol_tab[*(s + 2)]);
|
||||||
else
|
else
|
||||||
interp.feedData();
|
interp.feedData();
|
||||||
|
|
||||||
|
@ -386,15 +368,15 @@ static int16 *mix_signed_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint3
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_unsigned_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
static int16 * mix_unsigned_mono_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
{
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
uint32 fp_pos = *fp_pos_ptr;
|
uint32 fp_pos = *fp_pos_ptr;
|
||||||
byte *s = *s_ptr;
|
byte *s = *s_ptr;
|
||||||
uint len = *len_ptr;
|
uint len = *len_ptr;
|
||||||
|
|
||||||
int inc = 1, result;
|
int inc = 1, result;
|
||||||
CubicInterpolator interp(vol_tab[*s ^ 0x80], vol_tab[*(s+1) ^ 0x80], vol_tab[*(s+2) ^ 0x80]);
|
CubicInterpolator interp(vol_tab[*s ^ 0x80], vol_tab[*(s + 1) ^ 0x80], vol_tab[*(s + 2) ^ 0x80]);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
|
@ -412,8 +394,8 @@ static int16 *mix_unsigned_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uin
|
||||||
fp_pos &= 0x0000FFFF;
|
fp_pos &= 0x0000FFFF;
|
||||||
} while (!inc && len && (s < s_end));
|
} while (!inc && len && (s < s_end));
|
||||||
|
|
||||||
if (s+2 < s_end)
|
if (s + 2 < s_end)
|
||||||
interp.feedData(vol_tab[*(s+2) ^ 0x80]);
|
interp.feedData(vol_tab[*(s + 2) ^ 0x80]);
|
||||||
else
|
else
|
||||||
interp.feedData();
|
interp.feedData();
|
||||||
|
|
||||||
|
@ -425,23 +407,22 @@ static int16 *mix_unsigned_mono_8(int16 *data, uint * len_ptr, byte **s_ptr, uin
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_signed_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
static int16 * mix_signed_stereo_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
{
|
int fp_speed, const int16 * vol_tab, byte *s_end) {
|
||||||
warning("Mixing stereo signed 8 bit is not supported yet ");
|
warning("Mixing stereo signed 8 bit is not supported yet ");
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_unsigned_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
static int16 * mix_unsigned_stereo_8(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
{
|
|
||||||
uint32 fp_pos = *fp_pos_ptr;
|
uint32 fp_pos = *fp_pos_ptr;
|
||||||
byte *s = *s_ptr;
|
byte *s = *s_ptr;
|
||||||
uint len = *len_ptr;
|
uint len = *len_ptr;
|
||||||
|
|
||||||
int inc = 1;
|
int inc = 1;
|
||||||
CubicInterpolator left(vol_tab[*s ^ 0x80], vol_tab[*(s+2) ^ 0x80], vol_tab[*(s+4) ^ 0x80]);
|
CubicInterpolator left(vol_tab[*s ^ 0x80], vol_tab[*(s + 2) ^ 0x80], vol_tab[*(s + 4) ^ 0x80]);
|
||||||
CubicInterpolator right(vol_tab[*(s+1) ^ 0x80], vol_tab[*(s+3) ^ 0x80], vol_tab[*(s+5) ^ 0x80]);
|
CubicInterpolator right(vol_tab[*(s + 1) ^ 0x80], vol_tab[*(s + 3) ^ 0x80], vol_tab[*(s + 5) ^ 0x80]);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
do {
|
do {
|
||||||
|
@ -457,9 +438,9 @@ static int16 *mix_unsigned_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, u
|
||||||
fp_pos &= 0x0000FFFF;
|
fp_pos &= 0x0000FFFF;
|
||||||
} while (!inc && len && (s < s_end));
|
} while (!inc && len && (s < s_end));
|
||||||
|
|
||||||
if (s+5 < s_end) {
|
if (s + 5 < s_end) {
|
||||||
left.feedData(vol_tab[*(s+4) ^ 0x80]);
|
left.feedData(vol_tab[*(s + 4) ^ 0x80]);
|
||||||
right.feedData(vol_tab[*(s+5) ^ 0x80]);
|
right.feedData(vol_tab[*(s + 5) ^ 0x80]);
|
||||||
} else {
|
} else {
|
||||||
left.feedData();
|
left.feedData();
|
||||||
right.feedData();
|
right.feedData();
|
||||||
|
@ -473,9 +454,8 @@ static int16 *mix_unsigned_stereo_8(int16 *data, uint * len_ptr, byte **s_ptr, u
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_signed_mono_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
static int16 * mix_signed_mono_16(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
{
|
|
||||||
uint32 fp_pos = *fp_pos_ptr;
|
uint32 fp_pos = *fp_pos_ptr;
|
||||||
unsigned char volume = ((int)vol_tab[1]) / 8;
|
unsigned char volume = ((int)vol_tab[1]) / 8;
|
||||||
byte *s = *s_ptr;
|
byte *s = *s_ptr;
|
||||||
|
@ -499,16 +479,14 @@ static int16 *mix_signed_mono_16(int16 *data, uint * len_ptr, byte **s_ptr, uint
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_unsigned_mono_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
static int16 *mix_unsigned_mono_16(int16 *data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
{
|
|
||||||
warning("Mixing mono unsigned 16 bit is not supported yet ");
|
warning("Mixing mono unsigned 16 bit is not supported yet ");
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_signed_stereo_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
static int16 *mix_signed_stereo_16(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
{
|
|
||||||
uint32 fp_pos = *fp_pos_ptr;
|
uint32 fp_pos = *fp_pos_ptr;
|
||||||
unsigned char volume = ((int)vol_tab[1]) / 8;
|
unsigned char volume = ((int)vol_tab[1]) / 8;
|
||||||
byte *s = *s_ptr;
|
byte *s = *s_ptr;
|
||||||
|
@ -531,28 +509,29 @@ static int16 *mix_signed_stereo_16(int16 *data, uint * len_ptr, byte **s_ptr, ui
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
static int16 *mix_unsigned_stereo_16(int16 *data, uint * len_ptr, byte **s_ptr, uint32 *fp_pos_ptr,
|
static int16 * mix_unsigned_stereo_16(int16 * data, uint * len_ptr, byte ** s_ptr, uint32 * fp_pos_ptr,
|
||||||
int fp_speed, const int16 *vol_tab, byte *s_end)
|
int fp_speed, const int16 * vol_tab, byte * s_end) {
|
||||||
{
|
|
||||||
warning("Mixing stereo unsigned 16 bit is not supported yet ");
|
warning("Mixing stereo unsigned 16 bit is not supported yet ");
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16 *(*mixer_helper_table[8]) (int16 *data, uint * len_ptr, byte **s_ptr,
|
static int16 * (*mixer_helper_table[8]) (int16 * data, uint * len_ptr, byte ** s_ptr,
|
||||||
uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab,
|
uint32 * fp_pos_ptr, int fp_speed, const int16 * vol_tab,
|
||||||
byte *s_end) = {
|
byte * s_end) = {
|
||||||
mix_signed_mono_8, mix_unsigned_mono_8, mix_signed_stereo_8, mix_unsigned_stereo_8,
|
mix_signed_mono_8, mix_unsigned_mono_8,
|
||||||
mix_signed_mono_16, mix_unsigned_mono_16, mix_signed_stereo_16, mix_unsigned_stereo_16};
|
mix_signed_stereo_8, mix_unsigned_stereo_8,
|
||||||
|
mix_signed_mono_16, mix_unsigned_mono_16,
|
||||||
|
mix_signed_stereo_16, mix_unsigned_stereo_16
|
||||||
|
};
|
||||||
|
|
||||||
void SoundMixer::Channel_RAW::mix(int16 *data, uint len)
|
void SoundMixer::ChannelRaw::mix(int16 * data, uint len) {
|
||||||
{
|
|
||||||
byte *s, *s_org = NULL;
|
byte *s, *s_org = NULL;
|
||||||
uint32 fp_pos;
|
uint32 fp_pos;
|
||||||
byte *end;
|
byte *end;
|
||||||
|
|
||||||
if (_to_be_destroyed) {
|
if (_toBeDestroyed) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,11 +544,11 @@ void SoundMixer::Channel_RAW::mix(int16 *data, uint len)
|
||||||
*/
|
*/
|
||||||
if (_flags & FLAG_FILE) {
|
if (_flags & FLAG_FILE) {
|
||||||
/* determine how many samples to read from the file */
|
/* determine how many samples to read from the file */
|
||||||
uint num = len * _fp_speed >> 16;
|
uint num = len * _fpSpeed >> 16;
|
||||||
|
|
||||||
s_org = (byte *)malloc(num);
|
s_org = (byte *)malloc(num);
|
||||||
if (s_org == NULL)
|
if (s_org == NULL)
|
||||||
error("Channel_RAW::mix out of memory");
|
error("ChannelRaw::mix out of memory");
|
||||||
|
|
||||||
uint num_read = fread(s_org, 1, num, (FILE *) _ptr);
|
uint num_read = fread(s_org, 1, num, (FILE *) _ptr);
|
||||||
if (num - num_read != 0)
|
if (num - num_read != 0)
|
||||||
|
@ -580,141 +559,116 @@ void SoundMixer::Channel_RAW::mix(int16 *data, uint len)
|
||||||
end = s_org + num;
|
end = s_org + num;
|
||||||
} else {
|
} else {
|
||||||
s = (byte *)_ptr + _pos;
|
s = (byte *)_ptr + _pos;
|
||||||
fp_pos = _fp_pos;
|
fp_pos = _fpPos;
|
||||||
end = (byte *)_ptr + _realsize;
|
end = (byte *)_ptr + _realSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32 fp_speed = _fp_speed;
|
const uint32 fp_speed = _fpSpeed;
|
||||||
const int16 *vol_tab = _mixer->_volume_table;
|
const int16 *vol_tab = _mixer->_volumeTable;
|
||||||
|
|
||||||
mixer_helper_table[_flags & 0x07] (data, &len, &s, &fp_pos, fp_speed, vol_tab, end);
|
mixer_helper_table[_flags & 0x07] (data, &len, &s, &fp_pos, fp_speed, vol_tab, end);
|
||||||
|
|
||||||
_pos = s - (byte *)_ptr;
|
_pos = s - (byte *)_ptr;
|
||||||
_fp_pos = fp_pos;
|
_fpPos = fp_pos;
|
||||||
|
|
||||||
if (_flags & FLAG_FILE) {
|
if (_flags & FLAG_FILE) {
|
||||||
free(s_org);
|
free(s_org);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_size < 1)
|
if (_size < 1)
|
||||||
real_destroy();
|
realDestroy();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_RAW::real_destroy()
|
void SoundMixer::ChannelRaw::realDestroy() {
|
||||||
{
|
|
||||||
if (_flags & FLAG_AUTOFREE)
|
if (_flags & FLAG_AUTOFREE)
|
||||||
free(_ptr);
|
free(_ptr);
|
||||||
_mixer->uninsert(this);
|
_mixer->unInsert(this);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STREAM mixer */
|
SoundMixer::ChannelStream::ChannelStream(SoundMixer * mixer, void * sound, uint32 size, uint rate,
|
||||||
SoundMixer::Channel_STREAM::Channel_STREAM(SoundMixer *mixer, void *sound, uint32 size, uint rate,
|
byte flags) {
|
||||||
byte flags)
|
|
||||||
{
|
|
||||||
_mixer = mixer;
|
_mixer = mixer;
|
||||||
_flags = flags;
|
_flags = flags;
|
||||||
_buffer_size = 1024 * size;
|
_bufferSize = 1024 * size;
|
||||||
_ptr = (byte *)malloc(_buffer_size);
|
_ptr = (byte *)malloc(_bufferSize);
|
||||||
memcpy(_ptr, sound, size);
|
memcpy(_ptr, sound, size);
|
||||||
_end_of_data = _ptr + size;
|
_endOfData = _ptr + size;
|
||||||
if (_flags & FLAG_AUTOFREE)
|
if (_flags & FLAG_AUTOFREE)
|
||||||
free(sound);
|
free(sound);
|
||||||
_pos = _ptr;
|
_pos = _ptr;
|
||||||
_fp_pos = 0;
|
_fpPos = 0;
|
||||||
_fp_speed = (1 << 16) * rate / mixer->_output_rate;
|
_fpSpeed = (1 << 16) * rate / mixer->_outputRate;
|
||||||
_to_be_destroyed = false;
|
_toBeDestroyed = false;
|
||||||
|
|
||||||
/* adjust the magnitute to prevent division error */
|
/* adjust the magnitute to prevent division error */
|
||||||
while (size & 0xFFFF0000)
|
while (size & 0xFFFF0000)
|
||||||
size >>= 1, rate = (rate >> 1) + 1;
|
size >>= 1, rate = (rate >> 1) + 1;
|
||||||
|
|
||||||
|
|
||||||
_rate = rate;
|
_rate = rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_STREAM::append(void *data, uint32 len)
|
void SoundMixer::ChannelStream::append(void * data, uint32 len) {
|
||||||
{
|
byte *new_end = _endOfData + len;
|
||||||
byte *new_end = _end_of_data + len;
|
|
||||||
byte *cur_pos = _pos; /* This is just to prevent the variable to move during the tests :-) */
|
byte *cur_pos = _pos; /* This is just to prevent the variable to move during the tests :-) */
|
||||||
if (new_end > (_ptr + _buffer_size)) {
|
if (new_end > (_ptr + _bufferSize)) {
|
||||||
/* Wrap-around case */
|
/* Wrap-around case */
|
||||||
new_end = _ptr + len - ((_ptr + _buffer_size) - _end_of_data);
|
new_end = _ptr + len - ((_ptr + _bufferSize) - _endOfData);
|
||||||
if ((_end_of_data < cur_pos) || (new_end >= cur_pos)) {
|
if ((_endOfData < cur_pos) || (new_end >= cur_pos)) {
|
||||||
warning("Mixer full... Trying to not break too much ");
|
warning("Mixer full... Trying to not break too much ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(_end_of_data, data, (_ptr + _buffer_size) - _end_of_data);
|
memcpy(_endOfData, data, (_ptr + _bufferSize) - _endOfData);
|
||||||
memcpy(_ptr, (byte *)data + ((_ptr + _buffer_size) - _end_of_data),
|
memcpy(_ptr, (byte *)data + ((_ptr + _bufferSize) - _endOfData),
|
||||||
len - ((_ptr + _buffer_size) - _end_of_data));
|
len - ((_ptr + _bufferSize) - _endOfData));
|
||||||
} else {
|
} else {
|
||||||
if ((_end_of_data < cur_pos) && (new_end >= cur_pos)) {
|
if ((_endOfData < cur_pos) && (new_end >= cur_pos)) {
|
||||||
warning("Mixer full... Trying to not break too much ");
|
warning("Mixer full... Trying to not break too much ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(_end_of_data, data, len);
|
memcpy(_endOfData, data, len);
|
||||||
}
|
}
|
||||||
_end_of_data = new_end;
|
_endOfData = new_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_STREAM::mix(int16 *data, uint len)
|
void SoundMixer::ChannelStream::mix(int16 * data, uint len) {
|
||||||
{
|
|
||||||
uint32 fp_pos;
|
uint32 fp_pos;
|
||||||
const uint32 fp_speed = _fp_speed;
|
const uint32 fp_speed = _fpSpeed;
|
||||||
const int16 *vol_tab = _mixer->_volume_table;
|
const int16 * vol_tab = _mixer->_volumeTable;
|
||||||
byte *end_of_data = _end_of_data;
|
byte * end_of_data = _endOfData;
|
||||||
|
|
||||||
if (_to_be_destroyed) {
|
if (_toBeDestroyed) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_pos = _fp_pos;
|
fp_pos = _fpPos;
|
||||||
|
|
||||||
if (_pos < end_of_data) {
|
if (_pos < end_of_data) {
|
||||||
mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data);
|
mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data);
|
||||||
} else {
|
} else {
|
||||||
// mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab,
|
_toBeDestroyed = true;
|
||||||
// _ptr + _buffer_size);
|
|
||||||
// if (len != 0) {
|
|
||||||
// _pos = _ptr;
|
|
||||||
// mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab,
|
|
||||||
// end_of_data);
|
|
||||||
// } else
|
|
||||||
_to_be_destroyed = true;
|
|
||||||
}
|
}
|
||||||
if (len != 0) {
|
|
||||||
// FIXME: BBrox, what does this mean? :)
|
_fpPos = fp_pos;
|
||||||
// Commented by Ender to remove non-existant
|
|
||||||
// streamer bug in Dig smush movies.
|
|
||||||
//warning("Streaming underflow of %d bytes", len);
|
|
||||||
//real_destroy();
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
_fp_pos = fp_pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_STREAM::real_destroy()
|
void SoundMixer::ChannelStream::realDestroy() {
|
||||||
{
|
|
||||||
free(_ptr);
|
free(_ptr);
|
||||||
_mixer->uninsert(this);
|
_mixer->unInsert(this);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* MP3 mixer goes here */
|
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
SoundMixer::Channel_MP3::Channel_MP3(SoundMixer *mixer, void *sound, uint size, byte flags)
|
SoundMixer::ChannelMP3::ChannelMP3(SoundMixer * mixer, void * sound, uint size, byte flags) {
|
||||||
{
|
|
||||||
_mixer = mixer;
|
_mixer = mixer;
|
||||||
_flags = flags;
|
_flags = flags;
|
||||||
_pos_in_frame = 0xFFFFFFFF;
|
_posInFrame = 0xFFFFFFFF;
|
||||||
_position = 0;
|
_position = 0;
|
||||||
_size = size;
|
_size = size;
|
||||||
_ptr = sound;
|
_ptr = sound;
|
||||||
_to_be_destroyed = false;
|
_toBeDestroyed = false;
|
||||||
|
|
||||||
mad_stream_init(&_stream);
|
mad_stream_init(&_stream);
|
||||||
#ifdef _WIN32_WCE
|
#ifdef _WIN32_WCE
|
||||||
|
@ -735,11 +689,10 @@ SoundMixer::Channel_MP3::Channel_MP3(SoundMixer *mixer, void *sound, uint size,
|
||||||
When using Lame, it seems that the sound starts to have some volume about 50 ms
|
When using Lame, it seems that the sound starts to have some volume about 50 ms
|
||||||
from the start of the sound => we skip about 2 frames (at 22.05 khz).
|
from the start of the sound => we skip about 2 frames (at 22.05 khz).
|
||||||
*/
|
*/
|
||||||
_silence_cut = 576 * 2;
|
_silenceCut = 576 * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int scale_sample(mad_fixed_t sample)
|
static inline int scale_sample(mad_fixed_t sample) {
|
||||||
{
|
|
||||||
/* round */
|
/* round */
|
||||||
sample += (1L << (MAD_F_FRACBITS - 16));
|
sample += (1L << (MAD_F_FRACBITS - 16));
|
||||||
|
|
||||||
|
@ -753,44 +706,43 @@ static inline int scale_sample(mad_fixed_t sample)
|
||||||
return sample >> (MAD_F_FRACBITS + 2 - 16);
|
return sample >> (MAD_F_FRACBITS + 2 - 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_MP3::mix(int16 *data, uint len)
|
void SoundMixer::ChannelMP3::mix(int16 * data, uint len) {
|
||||||
{
|
mad_fixed_t const * ch;
|
||||||
mad_fixed_t const *ch;
|
const int16 * vol_tab = _mixer->_volumeTable;
|
||||||
const int16 *vol_tab = _mixer->_volume_table;
|
|
||||||
unsigned char volume = ((int)vol_tab[1]) / 8;
|
unsigned char volume = ((int)vol_tab[1]) / 8;
|
||||||
|
|
||||||
if (_to_be_destroyed) {
|
if (_toBeDestroyed) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = _synth.pcm.samples[0] + _pos_in_frame;
|
ch = _synth.pcm.samples[0] + _posInFrame;
|
||||||
|
|
||||||
/* Skip _silence_cut a the start */
|
/* Skip _silence_cut a the start */
|
||||||
if ((_pos_in_frame < _synth.pcm.length) && (_silence_cut > 0)) {
|
if ((_posInFrame < _synth.pcm.length) && (_silenceCut > 0)) {
|
||||||
uint32 diff = _synth.pcm.length - _pos_in_frame;
|
uint32 diff = _synth.pcm.length - _posInFrame;
|
||||||
|
|
||||||
if (diff > _silence_cut)
|
if (diff > _silenceCut)
|
||||||
diff = _silence_cut;
|
diff = _silenceCut;
|
||||||
_silence_cut -= diff;
|
_silenceCut -= diff;
|
||||||
ch += diff;
|
ch += diff;
|
||||||
_pos_in_frame += diff;
|
_posInFrame += diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((_pos_in_frame < _synth.pcm.length) && (len > 0)) {
|
while ((_posInFrame < _synth.pcm.length) && (len > 0)) {
|
||||||
int16 sample = (int16)((scale_sample(*ch) * volume) / 32);
|
int16 sample = (int16)((scale_sample(*ch) * volume) / 32);
|
||||||
*data++ += sample;
|
*data++ += sample;
|
||||||
*data++ += sample;
|
*data++ += sample;
|
||||||
len--;
|
len--;
|
||||||
ch++;
|
ch++;
|
||||||
_pos_in_frame++;
|
_posInFrame++;
|
||||||
}
|
}
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_position >= _size) {
|
if (_position >= _size) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,23 +752,22 @@ void SoundMixer::Channel_MP3::mix(int16 *data, uint len)
|
||||||
if (mad_frame_decode(&_frame, &_stream) == -1) {
|
if (mad_frame_decode(&_frame, &_stream) == -1) {
|
||||||
/* End of audio... */
|
/* End of audio... */
|
||||||
if (_stream.error == MAD_ERROR_BUFLEN) {
|
if (_stream.error == MAD_ERROR_BUFLEN) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
} else if (!MAD_RECOVERABLE(_stream.error)) {
|
} else if (!MAD_RECOVERABLE(_stream.error)) {
|
||||||
error("MAD frame decode error !");
|
error("MAD frame decode error !");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mad_synth_frame(&_synth, &_frame);
|
mad_synth_frame(&_synth, &_frame);
|
||||||
_pos_in_frame = 0;
|
_posInFrame = 0;
|
||||||
_position = (unsigned char *)_stream.next_frame - (unsigned char *)_ptr;
|
_position = (unsigned char *)_stream.next_frame - (unsigned char *)_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_MP3::real_destroy()
|
void SoundMixer::ChannelMP3::realDestroy() {
|
||||||
{
|
|
||||||
if (_flags & FLAG_AUTOFREE)
|
if (_flags & FLAG_AUTOFREE)
|
||||||
free(_ptr);
|
free(_ptr);
|
||||||
_mixer->uninsert(this);
|
_mixer->unInsert(this);
|
||||||
mad_synth_finish(&_synth);
|
mad_synth_finish(&_synth);
|
||||||
mad_frame_finish(&_frame);
|
mad_frame_finish(&_frame);
|
||||||
mad_stream_finish(&_stream);
|
mad_stream_finish(&_stream);
|
||||||
|
@ -824,19 +775,17 @@ void SoundMixer::Channel_MP3::real_destroy()
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MP3 CD music */
|
|
||||||
#define MP3CD_BUFFERING_SIZE 131072
|
#define MP3CD_BUFFERING_SIZE 131072
|
||||||
|
|
||||||
SoundMixer::Channel_MP3_CDMUSIC::Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE * file,
|
SoundMixer::ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer * mixer, FILE * file,
|
||||||
mad_timer_t duration)
|
mad_timer_t duration){
|
||||||
{
|
|
||||||
_mixer = mixer;
|
_mixer = mixer;
|
||||||
_file = file;
|
_file = file;
|
||||||
_duration = duration;
|
_duration = duration;
|
||||||
_initialized = false;
|
_initialized = false;
|
||||||
_buffer_size = MP3CD_BUFFERING_SIZE;
|
_bufferSize = MP3CD_BUFFERING_SIZE;
|
||||||
_ptr = malloc(MP3CD_BUFFERING_SIZE);
|
_ptr = malloc(MP3CD_BUFFERING_SIZE);
|
||||||
_to_be_destroyed = false;
|
_toBeDestroyed = false;
|
||||||
|
|
||||||
mad_stream_init(&_stream);
|
mad_stream_init(&_stream);
|
||||||
#ifdef _WIN32_WCE
|
#ifdef _WIN32_WCE
|
||||||
|
@ -847,24 +796,23 @@ SoundMixer::Channel_MP3_CDMUSIC::Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE * f
|
||||||
mad_synth_init(&_synth);
|
mad_synth_init(&_synth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len)
|
void SoundMixer::ChannelMP3CDMusic::mix(int16 * data, uint len) {
|
||||||
{
|
|
||||||
mad_fixed_t const *ch;
|
mad_fixed_t const *ch;
|
||||||
mad_timer_t frame_duration;
|
mad_timer_t frame_duration;
|
||||||
unsigned char volume = _mixer->_music_volume / 8;
|
unsigned char volume = _mixer->_musicVolume / 8;
|
||||||
|
|
||||||
if (_to_be_destroyed) {
|
if (_toBeDestroyed) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_initialized) {
|
if (!_initialized) {
|
||||||
int skip_loop;
|
int skip_loop;
|
||||||
// just skipped
|
// just skipped
|
||||||
memset(_ptr, 0, _buffer_size);
|
memset(_ptr, 0, _bufferSize);
|
||||||
_size = fread(_ptr, 1, _buffer_size, _file);
|
_size = fread(_ptr, 1, _bufferSize, _file);
|
||||||
if (!_size) {
|
if (!_size) {
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Resync
|
// Resync
|
||||||
|
@ -880,7 +828,7 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len)
|
||||||
} else {
|
} else {
|
||||||
if (!MAD_RECOVERABLE(_stream.error)) {
|
if (!MAD_RECOVERABLE(_stream.error)) {
|
||||||
debug(1, "Unrecoverable error while skipping !");
|
debug(1, "Unrecoverable error while skipping !");
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -890,24 +838,24 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len)
|
||||||
mad_synth_mute(&_synth);
|
mad_synth_mute(&_synth);
|
||||||
// Resume decoding
|
// Resume decoding
|
||||||
if (mad_frame_decode(&_frame, &_stream) == 0) {
|
if (mad_frame_decode(&_frame, &_stream) == 0) {
|
||||||
_pos_in_frame = 0;
|
_posInFrame = 0;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
} else {
|
} else {
|
||||||
debug(1, "Cannot resume decoding");
|
debug(1, "Cannot resume decoding");
|
||||||
real_destroy();
|
realDestroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// Get samples, play samples ...
|
// Get samples, play samples ...
|
||||||
ch = _synth.pcm.samples[0] + _pos_in_frame;
|
ch = _synth.pcm.samples[0] + _posInFrame;
|
||||||
while ((_pos_in_frame < _synth.pcm.length) && (len > 0)) {
|
while ((_posInFrame < _synth.pcm.length) && (len > 0)) {
|
||||||
int16 sample = (int16)((scale_sample(*ch++) * volume) / 32);
|
int16 sample = (int16)((scale_sample(*ch++) * volume) / 32);
|
||||||
*data++ += sample;
|
*data++ += sample;
|
||||||
*data++ += sample;
|
*data++ += sample;
|
||||||
len--;
|
len--;
|
||||||
_pos_in_frame++;
|
_posInFrame++;
|
||||||
}
|
}
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -923,13 +871,13 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len)
|
||||||
int not_decoded;
|
int not_decoded;
|
||||||
|
|
||||||
if (!_stream.next_frame) {
|
if (!_stream.next_frame) {
|
||||||
memset(_ptr, 0, _buffer_size + MAD_BUFFER_GUARD);
|
memset(_ptr, 0, _bufferSize + MAD_BUFFER_GUARD);
|
||||||
_size = fread(_ptr, 1, _buffer_size, _file);
|
_size = fread(_ptr, 1, _bufferSize, _file);
|
||||||
not_decoded = 0;
|
not_decoded = 0;
|
||||||
} else {
|
} else {
|
||||||
not_decoded = _stream.bufend - _stream.next_frame;
|
not_decoded = _stream.bufend - _stream.next_frame;
|
||||||
memcpy(_ptr, _stream.next_frame, not_decoded);
|
memcpy(_ptr, _stream.next_frame, not_decoded);
|
||||||
_size = fread((unsigned char *)_ptr + not_decoded, 1, _buffer_size - not_decoded, _file);
|
_size = fread((unsigned char *)_ptr + not_decoded, 1, _bufferSize - not_decoded, _file);
|
||||||
}
|
}
|
||||||
_stream.error = (enum mad_error)0;
|
_stream.error = (enum mad_error)0;
|
||||||
// Restream
|
// Restream
|
||||||
|
@ -942,19 +890,17 @@ void SoundMixer::Channel_MP3_CDMUSIC::mix(int16 *data, uint len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mad_synth_frame(&_synth, &_frame);
|
mad_synth_frame(&_synth, &_frame);
|
||||||
_pos_in_frame = 0;
|
_posInFrame = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundMixer::Channel_MP3_CDMUSIC::sound_finished()
|
bool SoundMixer::ChannelMP3CDMusic::soundFinished() {
|
||||||
{
|
|
||||||
return mad_timer_compare(_duration, mad_timer_zero) <= 0;
|
return mad_timer_compare(_duration, mad_timer_zero) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMixer::Channel_MP3_CDMUSIC::real_destroy()
|
void SoundMixer::ChannelMP3CDMusic::realDestroy() {
|
||||||
{
|
|
||||||
free(_ptr);
|
free(_ptr);
|
||||||
_mixer->uninsert(this);
|
_mixer->unInsert(this);
|
||||||
mad_synth_finish(&_synth);
|
mad_synth_finish(&_synth);
|
||||||
mad_frame_finish(&_frame);
|
mad_frame_finish(&_frame);
|
||||||
mad_stream_finish(&_stream);
|
mad_stream_finish(&_stream);
|
||||||
|
@ -962,5 +908,4 @@ void SoundMixer::Channel_MP3_CDMUSIC::real_destroy()
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
140
sound/mixer.h
140
sound/mixer.h
|
@ -30,110 +30,112 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef uint32 PlayingSoundHandle;
|
typedef uint32 PlayingSoundHandle;
|
||||||
|
|
||||||
class SoundMixer {
|
class SoundMixer {
|
||||||
private:
|
private:
|
||||||
class Channel {
|
class Channel {
|
||||||
public:
|
public:
|
||||||
bool _to_be_destroyed;
|
bool _toBeDestroyed;
|
||||||
virtual void mix(int16 *data, uint len) = 0;
|
virtual void mix(int16 *data, uint len) = 0;
|
||||||
void destroy() {
|
void destroy() {
|
||||||
_to_be_destroyed = true;
|
_toBeDestroyed = true;
|
||||||
} virtual void real_destroy() = 0;
|
}
|
||||||
|
virtual void realDestroy() = 0;
|
||||||
virtual void append(void *sound, uint32 size);
|
virtual void append(void *sound, uint32 size);
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
virtual bool sound_finished();
|
virtual bool soundFinished();
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class Channel_RAW:public Channel {
|
class ChannelRaw : public Channel {
|
||||||
SoundMixer *_mixer;
|
SoundMixer * _mixer;
|
||||||
void *_ptr;
|
void * _ptr;
|
||||||
uint32 _pos;
|
uint32 _pos;
|
||||||
uint32 _size;
|
uint32 _size;
|
||||||
uint32 _fp_speed;
|
uint32 _fpSpeed;
|
||||||
uint32 _fp_pos;
|
uint32 _fpPos;
|
||||||
uint32 _realsize, _rate;
|
uint32 _realSize, _rate;
|
||||||
byte _flags;
|
byte _flags;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void mix(int16 *data, uint len);
|
ChannelRaw(SoundMixer * mixer, void * sound, uint32 size, uint rate, byte flags);
|
||||||
Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags);
|
void mix(int16 * data, uint len);
|
||||||
void real_destroy();
|
void realDestroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Channel_STREAM:public Channel {
|
class ChannelStream : public Channel {
|
||||||
SoundMixer *_mixer;
|
SoundMixer * _mixer;
|
||||||
byte *_ptr;
|
byte * _ptr;
|
||||||
byte *_end_of_data;
|
byte * _endOfData;
|
||||||
byte *_pos;
|
byte * _pos;
|
||||||
uint32 _fp_speed;
|
uint32 _fpSpeed;
|
||||||
uint32 _fp_pos;
|
uint32 _fpPos;
|
||||||
uint32 _buffer_size;
|
uint32 _bufferSize;
|
||||||
uint32 _rate;
|
uint32 _rate;
|
||||||
byte _flags;
|
byte _flags;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void append(void *sound, uint32 size);
|
ChannelStream(SoundMixer * mixer, void * sound, uint32 size, uint rate, byte flags);
|
||||||
void mix(int16 *data, uint len);
|
void append(void * sound, uint32 size);
|
||||||
Channel_STREAM(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags);
|
void mix(int16 * data, uint len);
|
||||||
void real_destroy();
|
void realDestroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
|
|
||||||
class Channel_MP3:public Channel {
|
class ChannelMP3 : public Channel {
|
||||||
SoundMixer *_mixer;
|
SoundMixer * _mixer;
|
||||||
void *_ptr;
|
void *_ptr;
|
||||||
struct mad_stream _stream;
|
struct mad_stream _stream;
|
||||||
struct mad_frame _frame;
|
struct mad_frame _frame;
|
||||||
struct mad_synth _synth;
|
struct mad_synth _synth;
|
||||||
uint32 _silence_cut;
|
uint32 _silenceCut;
|
||||||
uint32 _pos_in_frame;
|
uint32 _posInFrame;
|
||||||
uint32 _position;
|
uint32 _position;
|
||||||
uint32 _size;
|
uint32 _size;
|
||||||
byte _flags;
|
byte _flags;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void mix(int16 *data, uint len);
|
ChannelMP3(SoundMixer * mixer, void *sound, uint size, byte flags);
|
||||||
Channel_MP3(SoundMixer *mixer, void *sound, uint size, byte flags);
|
void mix(int16 * data, uint len);
|
||||||
void real_destroy();
|
void realDestroy();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Channel_MP3_CDMUSIC:public Channel {
|
class ChannelMP3CDMusic:public Channel {
|
||||||
SoundMixer *_mixer;
|
SoundMixer * _mixer;
|
||||||
void *_ptr;
|
void * _ptr;
|
||||||
struct mad_stream _stream;
|
struct mad_stream _stream;
|
||||||
struct mad_frame _frame;
|
struct mad_frame _frame;
|
||||||
struct mad_synth _synth;
|
struct mad_synth _synth;
|
||||||
uint32 _pos_in_frame;
|
uint32 _posInFrame;
|
||||||
uint32 _size;
|
uint32 _size;
|
||||||
uint32 _buffer_size;
|
uint32 _bufferSize;
|
||||||
mad_timer_t _duration;
|
mad_timer_t _duration;
|
||||||
FILE *_file;
|
FILE * _file;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void mix(int16 *data, uint len);
|
ChannelMP3CDMusic(SoundMixer * mixer, FILE * file, mad_timer_t duration);
|
||||||
Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE * file, mad_timer_t duration);
|
void mix(int16 * data, uint len);
|
||||||
void real_destroy();
|
void realDestroy();
|
||||||
bool sound_finished();
|
bool soundFinished();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void on_generate_samples(void *s, byte *samples, int len);
|
static void onGenerateSamples(void * s, byte * samples, int len);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef void PremixProc (void *param, int16 *data, uint len);
|
typedef void PremixProc (void * param, int16 * data, uint len);
|
||||||
|
|
||||||
OSystem *_syst;
|
OSystem * _syst;
|
||||||
void *_mutex;
|
void * _mutex;
|
||||||
|
|
||||||
uint _output_rate;
|
uint _outputRate;
|
||||||
|
|
||||||
int16 *_volume_table;
|
int16 * _volumeTable;
|
||||||
int _music_volume;
|
int _musicVolume;
|
||||||
|
|
||||||
bool _paused;
|
bool _paused;
|
||||||
|
|
||||||
|
@ -141,18 +143,18 @@ public:
|
||||||
NUM_CHANNELS = 16,
|
NUM_CHANNELS = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
void *_premix_param;
|
void * _premixParam;
|
||||||
PremixProc *_premix_proc;
|
PremixProc * _premixProc;
|
||||||
|
|
||||||
Channel *_channels[NUM_CHANNELS];
|
Channel * _channels[NUM_CHANNELS];
|
||||||
PlayingSoundHandle *_handles[NUM_CHANNELS];
|
PlayingSoundHandle * _handles[NUM_CHANNELS];
|
||||||
|
|
||||||
SoundMixer();
|
SoundMixer();
|
||||||
~SoundMixer();
|
~SoundMixer();
|
||||||
|
|
||||||
int insert_at(PlayingSoundHandle *handle, int index, Channel * chan);
|
int insertAt(PlayingSoundHandle * handle, int index, Channel * chan);
|
||||||
void append(void *data, uint32 len);
|
void append(void * data, uint32 len);
|
||||||
void uninsert(Channel * chan);
|
void unInsert(Channel * chan);
|
||||||
|
|
||||||
/* start playing a raw sound */
|
/* start playing a raw sound */
|
||||||
enum {
|
enum {
|
||||||
|
@ -163,41 +165,41 @@ public:
|
||||||
FLAG_AUTOFREE = 8, /* sound buffer is freed automagically at the end of playing */
|
FLAG_AUTOFREE = 8, /* sound buffer is freed automagically at the end of playing */
|
||||||
FLAG_FILE = 16, /* sound is a FILE * that's read from */
|
FLAG_FILE = 16, /* sound is a FILE * that's read from */
|
||||||
};
|
};
|
||||||
int play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags);
|
int playRaw(PlayingSoundHandle * handle, void * sound, uint32 size, uint rate, byte flags);
|
||||||
int play_stream(PlayingSoundHandle *handle, int index, void *sound, uint32 size, uint rate,
|
int playStream(PlayingSoundHandle * handle, int index, void * sound, uint32 size, uint rate,
|
||||||
byte flags);
|
byte flags);
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
int play_mp3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags);
|
int playMP3(PlayingSoundHandle * handle, void * sound, uint32 size, byte flags);
|
||||||
int play_mp3_cdtrack(PlayingSoundHandle *handle, FILE * file, mad_timer_t duration);
|
int playMP3CDTrack(PlayingSoundHandle * handle, FILE * file, mad_timer_t duration);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Premix procedure, useful when using fmopl adlib */
|
/* Premix procedure, useful when using fmopl adlib */
|
||||||
void setup_premix(void *param, PremixProc *proc);
|
void setupPremix(void * param, PremixProc * proc);
|
||||||
|
|
||||||
/* mix */
|
/* mix */
|
||||||
void mix(int16 *buf, uint len);
|
void mix(int16 * buf, uint len);
|
||||||
|
|
||||||
/* stop all currently playing sounds */
|
/* stop all currently playing sounds */
|
||||||
void stop_all();
|
void stopAll();
|
||||||
|
|
||||||
/* stop playing a specific sound */
|
/* stop playing a specific sound */
|
||||||
void stop(PlayingSoundHandle psh);
|
void stop(PlayingSoundHandle psh);
|
||||||
void stop(int index);
|
void stop(int index);
|
||||||
|
|
||||||
/* append to existing sound */
|
/* append to existing sound */
|
||||||
int append(int index, void *sound, uint32 size, uint rate, byte flags);
|
int append(int index, void * sound, uint32 size, uint rate, byte flags);
|
||||||
|
|
||||||
/* is any channel active? */
|
/* is any channel active? */
|
||||||
bool has_active_channel();
|
bool hasActiveChannel();
|
||||||
|
|
||||||
/* bind to the OSystem object => mixer will be
|
/* bind to the OSystem object => mixer will be
|
||||||
* invoked automatically when samples need
|
* invoked automatically when samples need
|
||||||
* to be generated */
|
* to be generated */
|
||||||
bool bind_to_system(OSystem *syst);
|
bool bindToSystem(OSystem *syst);
|
||||||
|
|
||||||
/* set the volume, 0-256 */
|
/* set the volume, 0-256 */
|
||||||
void set_volume(int volume);
|
void setVolume(int volume);
|
||||||
void set_music_volume(int volume);
|
void setMusicVolume(int volume);
|
||||||
|
|
||||||
/* pause - unpause */
|
/* pause - unpause */
|
||||||
void pause(bool paused);
|
void pause(bool paused);
|
||||||
|
|
|
@ -137,19 +137,19 @@ void Sound::processSoundQues() {
|
||||||
byte * buffer = (byte*)malloc (size);
|
byte * buffer = (byte*)malloc (size);
|
||||||
memcpy(buffer, ptr, size);
|
memcpy(buffer, ptr, size);
|
||||||
if (chan == 1) {
|
if (chan == 1) {
|
||||||
_scumm->_mixer->play_raw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED);
|
_scumm->_mixer->playRaw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED);
|
||||||
}
|
}
|
||||||
else if (chan == 2) {
|
else if (chan == 2) {
|
||||||
_scumm->_mixer->play_raw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_STEREO);
|
_scumm->_mixer->playRaw(NULL, buffer, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_STEREO);
|
||||||
}
|
}
|
||||||
} else if (bits == 12) {
|
} else if (bits == 12) {
|
||||||
byte * buffer = NULL;
|
byte * buffer = NULL;
|
||||||
uint32 final_size = decode12BitsSample(ptr, &buffer, size);
|
uint32 final_size = decode12BitsSample(ptr, &buffer, size);
|
||||||
if (chan == 1) {
|
if (chan == 1) {
|
||||||
_scumm->_mixer->play_raw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS);
|
_scumm->_mixer->playRaw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS);
|
||||||
}
|
}
|
||||||
else if (chan == 2) {
|
else if (chan == 2) {
|
||||||
_scumm->_mixer->play_raw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO);
|
_scumm->_mixer->playRaw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ void Sound::playSound(int sound) {
|
||||||
// Allocate a sound buffer, copy the data into it, and play
|
// Allocate a sound buffer, copy the data into it, and play
|
||||||
char *sound = (char*)malloc(size);
|
char *sound = (char*)malloc(size);
|
||||||
memcpy(sound, ptr, size);
|
memcpy(sound, ptr, size);
|
||||||
_scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Support for Putt-Putt sounds - very hackish, too 8-)
|
// Support for Putt-Putt sounds - very hackish, too 8-)
|
||||||
|
@ -265,15 +265,15 @@ void Sound::playSound(int sound) {
|
||||||
|
|
||||||
// Allocate a sound buffer, copy the data into it, and play
|
// Allocate a sound buffer, copy the data into it, and play
|
||||||
char *sound = (char*)malloc(size);
|
char *sound = (char*)malloc(size);
|
||||||
memcpy(sound, ptr+8, size);
|
memcpy(sound, ptr + 8, size);
|
||||||
_scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (ptr != NULL && READ_UINT32_UNALIGNED(ptr) == MKID('Crea')) {
|
else if (ptr != NULL && READ_UINT32_UNALIGNED(ptr) == MKID('Crea')) {
|
||||||
int size, rate;
|
int size, rate;
|
||||||
char * sound = read_creative_voc_file(ptr, size, rate);
|
char * sound = read_creative_voc_file(ptr, size, rate);
|
||||||
if(sound != NULL) {
|
if(sound != NULL) {
|
||||||
_scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ void Sound::playSound(int sound) {
|
||||||
// Allocate a sound buffer, copy the data into it, and play
|
// Allocate a sound buffer, copy the data into it, and play
|
||||||
char *sound = (char*)malloc(size);
|
char *sound = (char*)malloc(size);
|
||||||
memcpy(sound, ptr + 33, size);
|
memcpy(sound, ptr + 33, size);
|
||||||
_scumm->_mixer->play_raw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playRaw(NULL, sound, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +386,7 @@ void Sound::playSound(int sound) {
|
||||||
|
|
||||||
// FIXME: Something in the header signifies looping. Need to track it down and add a
|
// FIXME: Something in the header signifies looping. Need to track it down and add a
|
||||||
// mixer flag or something.
|
// mixer flag or something.
|
||||||
_scumm->_mixer->play_raw(NULL, sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playRaw(NULL, sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,8 +676,8 @@ void Sound::setupSound() {
|
||||||
|
|
||||||
_scumm->_imuse->set_master_volume(_sound_volume_master);
|
_scumm->_imuse->set_master_volume(_sound_volume_master);
|
||||||
_scumm->_imuse->set_music_volume(_sound_volume_music);
|
_scumm->_imuse->set_music_volume(_sound_volume_music);
|
||||||
_scumm->_mixer->set_volume(_sound_volume_sfx);
|
_scumm->_mixer->setVolume(_sound_volume_sfx);
|
||||||
_scumm->_mixer->set_music_volume(_sound_volume_music);
|
_scumm->_mixer->setMusicVolume(_sound_volume_music);
|
||||||
}
|
}
|
||||||
_sfxFile = openSfxFile();
|
_sfxFile = openSfxFile();
|
||||||
}
|
}
|
||||||
|
@ -833,12 +833,12 @@ void * Sound::openSfxFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::stopSfxSound() {
|
void Sound::stopSfxSound() {
|
||||||
_scumm->_mixer->stop_all();
|
_scumm->_mixer->stopAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Sound::isSfxFinished() {
|
bool Sound::isSfxFinished() {
|
||||||
return !_scumm->_mixer->has_active_channel();
|
return !_scumm->_mixer->hasActiveChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Sound::decode12BitsSample(byte * src, byte ** dst, uint32 size) {
|
uint32 Sound::decode12BitsSample(byte * src, byte ** dst, uint32 size) {
|
||||||
|
@ -985,7 +985,7 @@ void Sound::bundleMusicHandler(Scumm * scumm) {
|
||||||
|
|
||||||
byte * buffer = NULL;
|
byte * buffer = NULL;
|
||||||
uint32 final_size = decode12BitsSample(ptr, &buffer, size);
|
uint32 final_size = decode12BitsSample(ptr, &buffer, size);
|
||||||
_scumm->_mixer->play_raw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO);
|
_scumm->_mixer->playRaw(NULL, buffer, final_size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::playBundleSound(char *sound) {
|
void Sound::playBundleSound(char *sound) {
|
||||||
|
@ -1042,7 +1042,7 @@ void Sound::playBundleSound(char *sound) {
|
||||||
|
|
||||||
byte * final = (byte *)malloc(size);
|
byte * final = (byte *)malloc(size);
|
||||||
memcpy(final, ptr, size);
|
memcpy(final, ptr, size);
|
||||||
_scumm->_mixer->play_raw(NULL, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
_scumm->_mixer->playRaw(NULL, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned) {
|
int Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned) {
|
||||||
|
@ -1051,14 +1051,14 @@ int Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned) {
|
||||||
byte flags = SoundMixer::FLAG_AUTOFREE;
|
byte flags = SoundMixer::FLAG_AUTOFREE;
|
||||||
if (isUnsigned)
|
if (isUnsigned)
|
||||||
flags |= SoundMixer::FLAG_UNSIGNED;
|
flags |= SoundMixer::FLAG_UNSIGNED;
|
||||||
return _scumm->_mixer->play_raw(NULL, sound, size, rate, flags);
|
return _scumm->_mixer->playRaw(NULL, sound, size, rate, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sound::playSfxSound_MP3(void *sound, uint32 size) {
|
int Sound::playSfxSound_MP3(void *sound, uint32 size) {
|
||||||
#ifdef COMPRESSED_SOUND_FILE
|
#ifdef COMPRESSED_SOUND_FILE
|
||||||
if (_soundsPaused)
|
if (_soundsPaused)
|
||||||
return -1;
|
return -1;
|
||||||
return _scumm->_mixer->play_mp3(NULL, sound, size, SoundMixer::FLAG_AUTOFREE);
|
return _scumm->_mixer->playMP3(NULL, sound, size, SoundMixer::FLAG_AUTOFREE);
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1200,7 +1200,7 @@ int Sound::playMP3CDTrack(int track, int num_loops, int start, int delay) {
|
||||||
|
|
||||||
if (_mp3_cd_playing == true)
|
if (_mp3_cd_playing == true)
|
||||||
_scumm->_mixer->stop(_mp3_index);
|
_scumm->_mixer->stop(_mp3_index);
|
||||||
_mp3_index = _scumm->_mixer->play_mp3_cdtrack(NULL, _mp3_tracks[index], duration);
|
_mp3_index = _scumm->_mixer->playMP3CDTrack(NULL, _mp3_tracks[index], duration);
|
||||||
_mp3_cd_playing = true;
|
_mp3_cd_playing = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1229,7 @@ int Sound::updateMP3CD() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_scumm->_mixer->_channels[_mp3_index]->sound_finished())
|
if (_scumm->_mixer->_channels[_mp3_index]->soundFinished())
|
||||||
stopMP3CD();
|
stopMP3CD();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue