mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-22 20:21:06 +00:00
DIRECTOR: Fix audio lifetime, implement b_puppetSound
This commit is contained in:
parent
3382e3e965
commit
59d6c5e5fd
@ -461,6 +461,7 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
|
|||||||
tag == MKTAG('R', 'T', 'E', '0') ||
|
tag == MKTAG('R', 'T', 'E', '0') ||
|
||||||
tag == MKTAG('R', 'T', 'E', '1') ||
|
tag == MKTAG('R', 'T', 'E', '1') ||
|
||||||
tag == MKTAG('R', 'T', 'E', '2') ||
|
tag == MKTAG('R', 'T', 'E', '2') ||
|
||||||
|
tag == MKTAG('s', 'n', 'd', ' ') ||
|
||||||
tag == MKTAG('L', 'c', 't', 'x') ||
|
tag == MKTAG('L', 'c', 't', 'x') ||
|
||||||
tag == MKTAG('L', 'n', 'a', 'm') ||
|
tag == MKTAG('L', 'n', 'a', 'm') ||
|
||||||
tag == MKTAG('L', 's', 'c', 'r'))
|
tag == MKTAG('L', 's', 'c', 'r'))
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "director/cachedmactext.h"
|
#include "director/cachedmactext.h"
|
||||||
#include "director/cast.h"
|
#include "director/cast.h"
|
||||||
#include "director/score.h"
|
#include "director/score.h"
|
||||||
|
#include "director/sound.h"
|
||||||
#include "director/stxt.h"
|
#include "director/stxt.h"
|
||||||
|
|
||||||
namespace Director {
|
namespace Director {
|
||||||
|
@ -30,10 +30,6 @@ namespace Graphics {
|
|||||||
struct Surface;
|
struct Surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Audio {
|
|
||||||
struct SeekableAudioStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
class SeekableReadStream;
|
class SeekableReadStream;
|
||||||
class ReadStreamEndian;
|
class ReadStreamEndian;
|
||||||
@ -43,6 +39,7 @@ namespace Director {
|
|||||||
|
|
||||||
class Stxt;
|
class Stxt;
|
||||||
class CachedMacText;
|
class CachedMacText;
|
||||||
|
class SNDDecoder;
|
||||||
|
|
||||||
class Cast {
|
class Cast {
|
||||||
public:
|
public:
|
||||||
@ -80,7 +77,7 @@ public:
|
|||||||
SoundCast(Common::ReadStreamEndian &stream, uint16 version);
|
SoundCast(Common::ReadStreamEndian &stream, uint16 version);
|
||||||
|
|
||||||
bool _looping;
|
bool _looping;
|
||||||
Audio::SeekableAudioStream *_audio;
|
SNDDecoder *_audio;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShapeCast : public Cast {
|
class ShapeCast : public Cast {
|
||||||
|
@ -23,11 +23,13 @@
|
|||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
|
||||||
#include "director/director.h"
|
#include "director/director.h"
|
||||||
|
#include "director/cast.h"
|
||||||
#include "director/lingo/lingo.h"
|
#include "director/lingo/lingo.h"
|
||||||
#include "director/lingo/lingo-builtins.h"
|
#include "director/lingo/lingo-builtins.h"
|
||||||
#include "director/lingo/lingo-code.h"
|
#include "director/lingo/lingo-code.h"
|
||||||
#include "director/frame.h"
|
#include "director/frame.h"
|
||||||
#include "director/score.h"
|
#include "director/score.h"
|
||||||
|
#include "director/sound.h"
|
||||||
#include "director/sprite.h"
|
#include "director/sprite.h"
|
||||||
#include "director/stxt.h"
|
#include "director/stxt.h"
|
||||||
|
|
||||||
@ -1394,11 +1396,33 @@ void LB::b_puppetPalette(int nargs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LB::b_puppetSound(int nargs) {
|
void LB::b_puppetSound(int nargs) {
|
||||||
g_lingo->convertVOIDtoString(0, nargs);
|
if (nargs != 1) {
|
||||||
|
error("b_puppetSound: expected 1 argument, got %d", nargs);
|
||||||
|
g_lingo->dropStack(nargs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Score *score = g_director->getCurrentScore();
|
||||||
|
|
||||||
g_lingo->printSTUBWithArglist("b_puppetSound", nargs);
|
DirectorSound *sound = g_director->getSoundManager();
|
||||||
|
Datum castMember = g_lingo->pop();
|
||||||
|
int castId = g_lingo->castIdFetch(castMember);
|
||||||
|
|
||||||
|
if (castId == 0) {
|
||||||
|
sound->stopSound(1);
|
||||||
|
} else {
|
||||||
|
Cast *cast = score->_loadedCast->getVal(castId);
|
||||||
|
if (cast->_type != kCastSound) {
|
||||||
|
error("b_puppetSound: attempted to play a non-SoundCast cast member");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SNDDecoder *sd = ((SoundCast *)cast)->_audio;
|
||||||
|
if (!sd) {
|
||||||
|
warning("b_puppetSound: no audio data attached to cast");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sound->playStream(*sd->getAudioStream(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
g_lingo->dropStack(nargs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LB::b_puppetSprite(int nargs) {
|
void LB::b_puppetSprite(int nargs) {
|
||||||
@ -1802,29 +1826,7 @@ void LB::b_cast(int nargs) {
|
|||||||
void LB::b_field(int nargs) {
|
void LB::b_field(int nargs) {
|
||||||
Datum d = g_lingo->pop();
|
Datum d = g_lingo->pop();
|
||||||
|
|
||||||
int id;
|
d.u.i = g_lingo->castIdFetch(d);
|
||||||
|
|
||||||
if (!g_director->getCurrentScore()) {
|
|
||||||
warning("b_field: Assigning to a field in an empty score");
|
|
||||||
d.u.i = 0;
|
|
||||||
d.type = INT;
|
|
||||||
g_lingo->push(d);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d.type == STRING) {
|
|
||||||
if (g_director->getCurrentScore()->_castsNames.contains(*d.u.s))
|
|
||||||
id = g_director->getCurrentScore()->_castsNames[*d.u.s];
|
|
||||||
else
|
|
||||||
error("b_field: Reference to non-existent field: %s", d.u.s->c_str());
|
|
||||||
} else if (d.type == INT || d.type == FLOAT) {
|
|
||||||
d.toInt();
|
|
||||||
id = d.u.i;
|
|
||||||
} else {
|
|
||||||
error("b_field: Incorrect reference type: %s", d.type2str());
|
|
||||||
}
|
|
||||||
|
|
||||||
d.u.i = id;
|
|
||||||
|
|
||||||
d.type = REFERENCE;
|
d.type = REFERENCE;
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ void Lingo::processIf(int startlabel, int endlabel, int finalElse) {
|
|||||||
int Lingo::castIdFetch(Datum &var) {
|
int Lingo::castIdFetch(Datum &var) {
|
||||||
Score *score = _vm->getCurrentScore();
|
Score *score = _vm->getCurrentScore();
|
||||||
if (!score) {
|
if (!score) {
|
||||||
warning("castFetch: Score is empty");
|
warning("castIdFetch: Score is empty");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,15 +497,15 @@ int Lingo::castIdFetch(Datum &var) {
|
|||||||
if (score->_castsNames.contains(*var.u.s))
|
if (score->_castsNames.contains(*var.u.s))
|
||||||
id = score->_castsNames[*var.u.s];
|
id = score->_castsNames[*var.u.s];
|
||||||
else
|
else
|
||||||
warning("castFetch: reference to non-existent cast member: %s", var.u.s->c_str());
|
warning("castIdFetch: reference to non-existent cast member: %s", var.u.s->c_str());
|
||||||
} else if (var.type == INT || var.type == FLOAT) {
|
} else if (var.type == INT || var.type == FLOAT) {
|
||||||
var.toInt();
|
var.toInt();
|
||||||
if (!score->_loadedCast->contains(var.u.i))
|
if (!score->_loadedCast->contains(var.u.i))
|
||||||
warning("castFetch: reference to non-existent cast ID: %d", var.u.i);
|
warning("castIdFetch: reference to non-existent cast ID: %d", var.u.i);
|
||||||
else
|
else
|
||||||
id = var.u.i;
|
id = var.u.i;
|
||||||
} else {
|
} else {
|
||||||
error("castFetch: was expecting STRING or INT, got %s", var.type2str());
|
error("castIdFetch: was expecting STRING or INT, got %s", var.type2str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
@ -698,27 +698,9 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
|
|||||||
|
|
||||||
Datum Lingo::getTheCast(Datum &id1, int field) {
|
Datum Lingo::getTheCast(Datum &id1, int field) {
|
||||||
Datum d;
|
Datum d;
|
||||||
int id = 0;
|
int id = g_lingo->castIdFetch(id1);
|
||||||
|
|
||||||
Score *score = _vm->getCurrentScore();
|
Score *score = _vm->getCurrentScore();
|
||||||
|
|
||||||
if (!score) {
|
|
||||||
warning("Lingo::getTheCast(): The cast %d field \"%s\" setting over non-active score", id, field2str(field));
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id1.type == INT) {
|
|
||||||
id = id1.u.i;
|
|
||||||
} else if (id1.type == STRING) {
|
|
||||||
if (score->_castsNames.contains(*id1.u.s)) {
|
|
||||||
id = score->_castsNames[*id1.u.s];
|
|
||||||
} else {
|
|
||||||
warning("Lingo::getTheCast(): Unknown the cast \"%s\"", id1.u.s->c_str());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warning("Lingo::getTheCast(): Unknown the cast id type: %s", id1.type2str());
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting default type
|
// Setting default type
|
||||||
d.type = INT;
|
d.type = INT;
|
||||||
|
|
||||||
|
@ -403,7 +403,8 @@ void Score::loadSpriteSounds(bool isSharedCast) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sndData != NULL && soundCast != NULL) {
|
if (sndData != NULL && soundCast != NULL) {
|
||||||
Audio::SeekableAudioStream *audio = makeSNDStream(sndData);
|
SNDDecoder *audio = new SNDDecoder();
|
||||||
|
audio->loadStream(*sndData);
|
||||||
soundCast->_audio = audio;
|
soundCast->_audio = audio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,10 +97,14 @@ void DirectorSound::playMCI(Audio::AudioStream &stream, uint32 from, uint32 to)
|
|||||||
|
|
||||||
void DirectorSound::playStream(Audio::AudioStream &stream, uint8 soundChannel) {
|
void DirectorSound::playStream(Audio::AudioStream &stream, uint8 soundChannel) {
|
||||||
Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(&stream);
|
Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(&stream);
|
||||||
|
playStream(*seekStream, soundChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectorSound::playStream(Audio::SeekableAudioStream &stream, uint8 soundChannel) {
|
||||||
if (soundChannel == 1)
|
if (soundChannel == 1)
|
||||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound1, seekStream);
|
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound1, &stream);
|
||||||
else
|
else
|
||||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound2, seekStream);
|
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound2, &stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectorSound::isChannelActive(uint8 channelID) {
|
bool DirectorSound::isChannelActive(uint8 channelID) {
|
||||||
@ -115,6 +119,15 @@ bool DirectorSound::isChannelActive(uint8 channelID) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DirectorSound::stopSound(uint8 channelID) {
|
||||||
|
if (channelID == 1) {
|
||||||
|
_mixer->stopHandle(*_sound1);
|
||||||
|
} else if (channelID == 2) {
|
||||||
|
_mixer->stopHandle(*_sound2);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void DirectorSound::stopSound() {
|
void DirectorSound::stopSound() {
|
||||||
_mixer->stopHandle(*_sound1);
|
_mixer->stopHandle(*_sound1);
|
||||||
_mixer->stopHandle(*_sound2);
|
_mixer->stopHandle(*_sound2);
|
||||||
@ -125,55 +138,78 @@ void DirectorSound::systemBeep() {
|
|||||||
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, 500, 150);
|
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, 500, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SNDDecoder::SNDDecoder() {
|
||||||
|
_data = nullptr;
|
||||||
|
_channels = 0;
|
||||||
|
_size = 0;
|
||||||
|
_rate = 0;
|
||||||
|
_flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SNDDecoder::~SNDDecoder() {
|
||||||
|
if (_data) {
|
||||||
|
free(_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SNDDecoder::loadStream(Common::SeekableSubReadStreamEndian &stream) {
|
||||||
|
if (_data) {
|
||||||
|
free(_data);
|
||||||
|
_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Audio::SeekableAudioStream *makeSNDStream(Common::SeekableSubReadStreamEndian *stream) {
|
|
||||||
if (debugChannelSet(5, kDebugLoading)) {
|
if (debugChannelSet(5, kDebugLoading)) {
|
||||||
debugC(5, kDebugLoading, "snd header:");
|
debugC(5, kDebugLoading, "snd header:");
|
||||||
stream->hexdump(0x4e);
|
stream.hexdump(0x4e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unk1
|
// unk1
|
||||||
for (uint32 i = 0; i < 0x14; i++) {
|
for (uint32 i = 0; i < 0x14; i++) {
|
||||||
stream->readByte();
|
stream.readByte();
|
||||||
}
|
}
|
||||||
uint16 channels = stream->readUint16();
|
_channels = stream.readUint16();
|
||||||
if (channels != 1 || channels != 2) {
|
if (!(_channels == 1 || _channels == 2)) {
|
||||||
warning("STUB: loadSpriteSounds: no support for old sound format");
|
warning("STUB: loadSpriteSounds: no support for old sound format");
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
uint16 rate = stream->readUint16();
|
_rate = stream.readUint16();
|
||||||
|
|
||||||
// unk2
|
// unk2
|
||||||
for (uint32 i = 0; i < 0x06; i++) {
|
for (uint32 i = 0; i < 0x06; i++) {
|
||||||
stream->readByte();
|
stream.readByte();
|
||||||
}
|
}
|
||||||
uint32 length = stream->readUint32();
|
uint32 length = stream.readUint32();
|
||||||
/*uint16 unk3 =*/stream->readUint16();
|
/*uint16 unk3 =*/stream.readUint16();
|
||||||
/*uint32 length_copy =*/stream->readUint32();
|
/*uint32 length_copy =*/stream.readUint32();
|
||||||
/*uint8 unk4 =*/stream->readByte();
|
/*uint8 unk4 =*/stream.readByte();
|
||||||
/*uint8 unk5 =*/stream->readByte();
|
/*uint8 unk5 =*/stream.readByte();
|
||||||
/*uint16 unk6 =*/stream->readUint16();
|
/*uint16 unk6 =*/stream.readUint16();
|
||||||
// unk7
|
// unk7
|
||||||
for (uint32 i = 0; i < 0x12; i++) {
|
for (uint32 i = 0; i < 0x12; i++) {
|
||||||
stream->readByte();
|
stream.readByte();
|
||||||
}
|
}
|
||||||
uint16 bits = stream->readUint16();
|
uint16 bits = stream.readUint16();
|
||||||
// unk8
|
// unk8
|
||||||
for (uint32 i = 0; i < 0x0c; i++) {
|
for (uint32 i = 0; i < 0x0c; i++) {
|
||||||
stream->readByte();
|
stream.readByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
byte flags = 0;
|
_flags = 0;
|
||||||
flags |= channels == 2 ? Audio::FLAG_STEREO : 0;
|
_flags |= _channels == 2 ? Audio::FLAG_STEREO : 0;
|
||||||
flags |= bits == 16 ? Audio::FLAG_16BITS : 0;
|
_flags |= bits == 16 ? Audio::FLAG_16BITS : 0;
|
||||||
flags |= bits == 8 ? Audio::FLAG_UNSIGNED : 0;
|
_flags |= bits == 8 ? Audio::FLAG_UNSIGNED : 0;
|
||||||
uint32 size = length * channels * (bits == 16 ? 2 : 1);
|
_size = length * _channels * (bits == 16 ? 2 : 1);
|
||||||
|
|
||||||
byte *data = (byte *)malloc(size);
|
_data = (byte *)malloc(_size);
|
||||||
assert(data);
|
assert(_data);
|
||||||
stream->read(data, size);
|
stream.read(_data, _size);
|
||||||
|
|
||||||
return Audio::makeRawStream(data, size, rate, flags);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Audio::SeekableAudioStream *SNDDecoder::getAudioStream() {
|
||||||
|
return Audio::makeRawStream(_data, _size, _rate, _flags, DisposeAfterUse::NO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,12 +50,29 @@ public:
|
|||||||
void playAIFF(Common::String filename, uint8 channelID);
|
void playAIFF(Common::String filename, uint8 channelID);
|
||||||
void playMCI(Audio::AudioStream &stream, uint32 from, uint32 to);
|
void playMCI(Audio::AudioStream &stream, uint32 from, uint32 to);
|
||||||
void playStream(Audio::AudioStream &stream, uint8 soundChannel);
|
void playStream(Audio::AudioStream &stream, uint8 soundChannel);
|
||||||
|
void playStream(Audio::SeekableAudioStream &stream, uint8 soundChannel);
|
||||||
void systemBeep();
|
void systemBeep();
|
||||||
bool isChannelActive(uint8 channelID);
|
bool isChannelActive(uint8 channelID);
|
||||||
|
void stopSound(uint8 channelID);
|
||||||
void stopSound();
|
void stopSound();
|
||||||
};
|
};
|
||||||
|
|
||||||
Audio::SeekableAudioStream *makeSNDStream(Common::SeekableSubReadStreamEndian *stream);
|
|
||||||
|
class SNDDecoder {
|
||||||
|
public:
|
||||||
|
SNDDecoder();
|
||||||
|
~SNDDecoder();
|
||||||
|
|
||||||
|
bool loadStream(Common::SeekableSubReadStreamEndian &stream);
|
||||||
|
Audio::SeekableAudioStream *getAudioStream();
|
||||||
|
|
||||||
|
private:
|
||||||
|
byte *_data;
|
||||||
|
uint16 _channels;
|
||||||
|
uint32 _size;
|
||||||
|
uint16 _rate;
|
||||||
|
byte _flags;
|
||||||
|
};
|
||||||
|
|
||||||
} // End of namespace Director
|
} // End of namespace Director
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user